From 13dbbc268367371ef8d32251153981858821a874 Mon Sep 17 00:00:00 2001 From: Vincent Sylvester Date: Sun, 13 Mar 2022 03:31:28 +0100 Subject: [PATCH] Remove tabs, indent code properly Signed-off-by: UbitUmarov --- OpenSim/Data/PGSQL/PGSQLFSAssetData.cs | 2 +- .../HttpServer/OSHttpServer/HttpInput.cs | 2 +- .../HttpServer/OSHttpServer/HttpInputItem.cs | 52 +- .../HttpServer/OSHttpServer/HttpParam.cs | 2 +- .../OSHttpServer/IHttpRequestParser.cs | 16 +- .../HttpServer/OSHttpServer/RequestCookies.cs | 8 +- OpenSim/Region/Application/OpenSimBase.cs | 8 +- .../World/AutoBackup/AutoBackupModule.cs | 14 +- .../PhysicsModules/BulletS/BSAPIUnman.cs | 4199 ++++++++------- .../Region/PhysicsModules/BulletS/BSAPIXNA.cs | 4773 +++++++++-------- .../BulletS/BSActorAvatarMove.cs | 707 +-- .../PhysicsModules/BulletS/BSActorHover.cs | 232 +- .../PhysicsModules/BulletS/BSActorLockAxis.cs | 316 +- .../BulletS/BSActorMoveToTarget.cs | 304 +- .../PhysicsModules/BulletS/BSActorSetForce.cs | 170 +- .../BulletS/BSActorSetTorque.cs | 172 +- .../Region/PhysicsModules/BulletS/BSActors.cs | 208 +- .../PhysicsModules/BulletS/BSApiTemplate.cs | 1483 +++-- .../PhysicsModules/BulletS/BSCharacter.cs | 1544 +++--- .../PhysicsModules/BulletS/BSConstraint.cs | 195 +- .../BulletS/BSConstraint6Dof.cs | 235 +- .../BulletS/BSConstraintCollection.cs | 229 +- .../BulletS/BSConstraintConeTwist.cs | 34 +- .../BulletS/BSConstraintSlider.cs | 35 +- .../BulletS/BSConstraintSpring.cs | 129 +- .../PhysicsModules/BulletS/BSLinkset.cs | 859 ++- .../BulletS/BSLinksetCompound.cs | 815 ++- .../BulletS/BSLinksetConstraints.cs | 1515 +++--- .../PhysicsModules/BulletS/BSMaterials.cs | 313 +- .../Region/PhysicsModules/BulletS/BSMotors.cs | 758 +-- .../Region/PhysicsModules/BulletS/BSParam.cs | 1744 +++--- .../PhysicsModules/BulletS/BSPhysObject.cs | 1266 ++--- .../Region/PhysicsModules/BulletS/BSPrim.cs | 3580 ++++++------- .../PhysicsModules/BulletS/BSPrimDisplaced.cs | 244 +- .../PhysicsModules/BulletS/BSPrimLinkable.cs | 584 +- .../BulletS/BSShapeCollection.cs | 702 +-- .../Region/PhysicsModules/BulletS/BSShapes.cs | 2661 +++++---- .../BulletS/BSTerrainHeightmap.cs | 270 +- .../BulletS/BSTerrainManager.cs | 977 ++-- .../PhysicsModules/BulletS/BSTerrainMesh.cs | 740 +-- .../PhysicsModules/BulletS/BulletSimData.cs | 482 +- .../ConvexDecompositionDotNet/HullUtils.cs | 8 +- OpenSim/Region/PhysicsModules/Ode/ODEApi.cs | 4 +- OpenSim/Region/PhysicsModules/ubOde/ODEApi.cs | 4 +- .../Implementation/Plugins/SensorRepeat.cs | 2 +- 45 files changed, 16302 insertions(+), 16295 deletions(-) diff --git a/OpenSim/Data/PGSQL/PGSQLFSAssetData.cs b/OpenSim/Data/PGSQL/PGSQLFSAssetData.cs index 59b857c61f..def1f4a173 100644 --- a/OpenSim/Data/PGSQL/PGSQLFSAssetData.cs +++ b/OpenSim/Data/PGSQL/PGSQLFSAssetData.cs @@ -183,7 +183,7 @@ namespace OpenSim.Data.PGSQL catch(Exception e) { m_log.Error("[PGSQL FSASSETS] Failed to store asset with ID " + meta.ID); - m_log.Error(e.ToString()); + m_log.Error(e.ToString()); return false; } } diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpInput.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpInput.cs index c6585b197c..e4701903a3 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpInput.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpInput.cs @@ -33,7 +33,7 @@ namespace OSHttpServer /// form name. /// if set to true all changes will be ignored. /// this constructor should only be used by Empty - protected HttpInput(string name, bool ignoreChanges) + protected HttpInput(string name, bool ignoreChanges) { _name = name; _ignoreChanges = ignoreChanges; diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpInputItem.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpInputItem.cs index 0ab7690618..2172c7da52 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpInputItem.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpInputItem.cs @@ -17,18 +17,18 @@ namespace OSHttpServer /// public class HttpInputItem : IHttpInput { - /// Representation of a non-initialized . + /// Representation of a non-initialized . public static readonly HttpInputItem Empty = new HttpInputItem(string.Empty, true); private readonly IDictionary _items = new Dictionary(); private readonly List _values = new List(); private string _name; private readonly bool _ignoreChanges; - - /// - /// Initializes an input item setting its name/identifier and value - /// - /// Parameter name/id - /// Parameter value + + /// + /// Initializes an input item setting its name/identifier and value + /// + /// Parameter name/id + /// Parameter value public HttpInputItem(string name, string value) { Name = name; @@ -41,20 +41,20 @@ namespace OSHttpServer _ignoreChanges = ignore; } - /// Creates a deep copy of the item specified - /// The item to copy - /// The function makes a deep copy of quite a lot which can be slow - public HttpInputItem(HttpInputItem item) - { - foreach (KeyValuePair pair in item._items) - _items.Add(pair.Key, pair.Value); - - foreach (string value in item._values) - _values.Add(value); - - _ignoreChanges = item._ignoreChanges; - _name = item.Name; - } + /// Creates a deep copy of the item specified + /// The item to copy + /// The function makes a deep copy of quite a lot which can be slow + public HttpInputItem(HttpInputItem item) + { + foreach (KeyValuePair pair in item._items) + _items.Add(pair.Key, pair.Value); + + foreach (string value in item._values) + _values.Add(value); + + _ignoreChanges = item._ignoreChanges; + _name = item.Name; + } /// /// Number of values @@ -147,16 +147,16 @@ namespace OSHttpServer return _items.ContainsKey(name) && _items[name].Value != null; } - /// Returns a formatted representation of the instance with the values of all contained parameters + /// Returns a formatted representation of the instance with the values of all contained parameters public override string ToString() { return ToString(string.Empty); } - /// - /// Outputs the string in a formatted manner - /// - /// A prefix to append, used internally + /// + /// Outputs the string in a formatted manner + /// + /// A prefix to append, used internally /// produce a query string public string ToString(string prefix, bool asQuerySting) { diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpParam.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpParam.cs index c1a14b6a57..7c0f056a69 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpParam.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpServer/HttpParam.cs @@ -17,7 +17,7 @@ namespace OSHttpServer private List _items = new List(); - /// Initialises the class to hold a value either from a post request or a querystring request + /// Initialises the class to hold a value either from a post request or a querystring request public HttpParam(IHttpInput form, IHttpInput query) { m_form = form; diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpServer/IHttpRequestParser.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpServer/IHttpRequestParser.cs index 953fab343c..9f192b5552 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpServer/IHttpRequestParser.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpServer/IHttpRequestParser.cs @@ -49,15 +49,15 @@ namespace OSHttpServer /// event EventHandler HeaderReceived; - /// - /// Clear parser state. - /// - void Clear(); + /// + /// Clear parser state. + /// + void Clear(); - /// - /// Gets or sets the log writer. - /// - ILogWriter LogWriter { get; set; } + /// + /// Gets or sets the log writer. + /// + ILogWriter LogWriter { get; set; } } /// diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpServer/RequestCookies.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpServer/RequestCookies.cs index 3a7f05de6e..13ade76600 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpServer/RequestCookies.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpServer/RequestCookies.cs @@ -146,10 +146,10 @@ namespace OSHttpServer #endregion - /// - /// Remove a cookie from the collection. - /// - /// Name of cookie. + /// + /// Remove a cookie from the collection. + /// + /// Name of cookie. public void Remove(string cookieName) { lock (_items) diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index db0c358eec..59a893d0d0 100755 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -1030,7 +1030,7 @@ namespace OpenSim regInfo.EstateSettings = EstateDataService.LoadEstateSettings(regInfo.RegionID, false); if (regInfo.EstateSettings.EstateID != 0) - return false; // estate info in the database did not change + return false; // estate info in the database did not change m_log.WarnFormat("[ESTATE] Region {0} is not part of an estate.", regInfo.RegionName); @@ -1161,10 +1161,10 @@ namespace OpenSim MainConsole.Instance.Output("Joining the estate failed. Please try again."); } } - } + } - return true; // need to update the database - } + return true; // need to update the database + } } public class OpenSimConfigSource diff --git a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs index e5bb59d9d8..2f706257fd 100755 --- a/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs +++ b/OpenSim/Region/OptionalModules/World/AutoBackup/AutoBackupModule.cs @@ -65,9 +65,9 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup /// AutoBackupModuleEnabled: True/False. Default: False. If True, use the auto backup module. /// if false module is disable and all rest is ignored /// AutoBackupInterval: Double, non-negative value. Default: 720 (12 hours). - /// The number of minutes between each backup attempt. + /// The number of minutes between each backup attempt. /// AutoBackupDir: String. Default: "." (the current directory). - /// A directory (absolute or relative) where backups should be saved. + /// A directory (absolute or relative) where backups should be saved. /// AutoBackupKeepFilesForDays remove files older than this number of days. 0 disables /// /// Next can be set on OpenSim.ini, as default, and or per region in Regions.ini @@ -81,14 +81,14 @@ namespace OpenSim.Region.OptionalModules.World.AutoBackup /// AutoBackupKeepFilesForDays /// Backup files older than this value (in days) are deleted during the current backup process, 0 will disable this and keep all backup files indefinitely /// AutoBackupScript: String. Default: not specified (disabled). - /// File path to an executable script or binary to run when an automatic backup is taken. + /// File path to an executable script or binary to run when an automatic backup is taken. /// The file should really be (Windows) an .exe or .bat, or (Linux/Mac) a shell script or binary. /// Trying to "run" directories, or things with weird file associations on Win32, might cause unexpected results! - /// argv[1] of the executed file/script will be the file name of the generated OAR. - /// If the process can't be spawned for some reason (file not found, no execute permission, etc), write a warning to the console. + /// argv[1] of the executed file/script will be the file name of the generated OAR. + /// If the process can't be spawned for some reason (file not found, no execute permission, etc), write a warning to the console. /// AutoBackupNaming: string. Default: Time. - /// One of three strings (case insensitive): - /// "Time": Current timestamp is appended to file name. An existing file will never be overwritten. + /// One of three strings (case insensitive): + /// "Time": Current timestamp is appended to file name. An existing file will never be overwritten. /// "Sequential": A number is appended to the file name. So if RegionName_x.oar exists, we'll save to RegionName_{x+1}.oar next. An existing file will never be overwritten. /// "Overwrite": Always save to file named "${AutoBackupDir}/RegionName.oar", even if we have to overwrite an existing file. /// diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs index 840e453b0c..595bc7443b 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIUnman.cs @@ -37,2106 +37,2105 @@ using OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -public sealed class BSAPIUnman : BSAPITemplate -{ - -private sealed class BulletWorldUnman : BulletWorld -{ - public IntPtr ptr; - public BulletWorldUnman(uint id, BSScene physScene, IntPtr xx) - : base(id, physScene) + public sealed class BSAPIUnman : BSAPITemplate { - ptr = xx; + + private sealed class BulletWorldUnman : BulletWorld + { + public IntPtr ptr; + public BulletWorldUnman(uint id, BSScene physScene, IntPtr xx) + : base(id, physScene) + { + ptr = xx; + } + } + + private sealed class BulletBodyUnman : BulletBody + { + public IntPtr ptr; + public BulletBodyUnman(uint id, IntPtr xx) + : base(id) + { + ptr = xx; + } + public override bool HasPhysicalBody + { + get { return ptr != IntPtr.Zero; } + } + public override void Clear() + { + ptr = IntPtr.Zero; + } + public override string AddrString + { + get { return ptr.ToString("X"); } + } + } + + private sealed class BulletShapeUnman : BulletShape + { + public IntPtr ptr; + public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) + : base() + { + ptr = xx; + shapeType = typ; + } + public override bool HasPhysicalShape + { + get { return ptr != IntPtr.Zero; } + } + public override void Clear() + { + ptr = IntPtr.Zero; + } + public override BulletShape Clone() + { + return new BulletShapeUnman(ptr, shapeType); + } + public override bool ReferenceSame(BulletShape other) + { + BulletShapeUnman otheru = other as BulletShapeUnman; + return (otheru != null) && (this.ptr == otheru.ptr); + + } + public override string AddrString + { + get { return ptr.ToString("X"); } + } + } + + private sealed class BulletConstraintUnman : BulletConstraint + { + public BulletConstraintUnman(IntPtr xx) : base() + { + ptr = xx; + } + public IntPtr ptr; + + public override void Clear() + { + ptr = IntPtr.Zero; + } + public override bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } } + + // Used for log messages for a unique display of the memory/object allocated to this instance + public override string AddrString + { + get { return ptr.ToString("X"); } + } + } + + // We pin the memory passed between the managed and unmanaged code. + GCHandle m_paramsHandle; + private GCHandle m_collisionArrayPinnedHandle; + private GCHandle m_updateArrayPinnedHandle; + + // Handle to the callback used by the unmanaged code to call into the managed code. + // Used for debug logging. + // Need to store the handle in a persistant variable so it won't be freed. + private BSAPICPP.DebugLogCallback m_DebugLogCallbackHandle; + + private BSScene PhysicsScene { get; set; } + + public override string BulletEngineName { get { return "BulletUnmanaged"; } } + public override string BulletEngineVersion { get; protected set; } + + public BSAPIUnman(string paramName, BSScene physScene) + { + PhysicsScene = physScene; + + // Do something fancy with the paramName to get the right DLL implementation + // like "Bullet-2.80-OpenCL-Intel" loading the version for Intel based OpenCL implementation, etc. + if (Util.IsWindows()) + Util.LoadArchSpecificWindowsDll("BulletSim.dll"); + // If not Windows, loading is performed by the + // Mono loader as specified in + // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". + } + + // Initialization and simulation + public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, + int maxCollisions, ref CollisionDesc[] collisionArray, + int maxUpdates, ref EntityProperties[] updateArray + ) + { + // Pin down the memory that will be used to pass object collisions and updates back from unmanaged code + m_paramsHandle = GCHandle.Alloc(parms, GCHandleType.Pinned); + m_collisionArrayPinnedHandle = GCHandle.Alloc(collisionArray, GCHandleType.Pinned); + m_updateArrayPinnedHandle = GCHandle.Alloc(updateArray, GCHandleType.Pinned); + + // If Debug logging level, enable logging from the unmanaged code + m_DebugLogCallbackHandle = null; + if (BSScene.m_log.IsDebugEnabled && PhysicsScene.PhysicsLogging.Enabled) + { + BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader); + if (PhysicsScene.PhysicsLogging.Enabled) + // The handle is saved in a variable to make sure it doesn't get freed after this call + m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLoggerPhysLog); + else + m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLogger); + } + + // Get the version of the DLL + // TODO: this doesn't work yet. Something wrong with marshaling the returned string. + // BulletEngineVersion = BulletSimAPI.GetVersion2(); + BulletEngineVersion = ""; + + // Call the unmanaged code with the buffers and other information + return new BulletWorldUnman(0, PhysicsScene, BSAPICPP.Initialize2(maxPosition, m_paramsHandle.AddrOfPinnedObject(), + maxCollisions, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), + maxUpdates, m_updateArrayPinnedHandle.AddrOfPinnedObject(), + m_DebugLogCallbackHandle)); + + } + + // Called directly from unmanaged code so don't do much + private void BulletLogger(string msg) + { + BSScene.m_log.Debug("[BULLETS UNMANAGED]:" + msg); + } + + // Called directly from unmanaged code so don't do much + private void BulletLoggerPhysLog(string msg) + { + PhysicsScene.DetailLog("[BULLETS UNMANAGED]:" + msg); + } + + public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, + out int updatedEntityCount, out int collidersCount) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount); + } + + public override void Shutdown(BulletWorld world) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.Shutdown2(worldu.ptr); + + if (m_paramsHandle.IsAllocated) + { + m_paramsHandle.Free(); + } + if (m_collisionArrayPinnedHandle.IsAllocated) + { + m_collisionArrayPinnedHandle.Free(); + } + if (m_updateArrayPinnedHandle.IsAllocated) + { + m_updateArrayPinnedHandle.Free(); + } + } + + public override bool PushUpdate(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.PushUpdate2(bodyu.ptr); + } + + public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + return BSAPICPP.UpdateParameter2(worldu.ptr, localID, parm, value); + } + + // ===================================================================================== + // Mesh, hull, shape and body creation helper routines + public override BulletShape CreateMeshShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.CreateMeshShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), + BSPhysicsShapeType.SHAPE_MESH); + } + + public override BulletShape CreateGImpactShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.CreateGImpactShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), + BSPhysicsShapeType.SHAPE_GIMPACT); + } + + public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), + BSPhysicsShapeType.SHAPE_HULL); + } + + public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman shapeu = meshShape as BulletShapeUnman; + return new BulletShapeUnman( + BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms), + BSPhysicsShapeType.SHAPE_HULL); + } + + public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman shapeu = meshShape as BulletShapeUnman; + return new BulletShapeUnman( + BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr), + BSPhysicsShapeType.SHAPE_CONVEXHULL); + } + + public override BulletShape CreateConvexHullShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), + BSPhysicsShapeType.SHAPE_CONVEXHULL); + } + + public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type); + } + + public override bool IsNativeShape(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + if (shapeu != null && shapeu.HasPhysicalShape) + return BSAPICPP.IsNativeShape2(shapeu.ptr); + return false; + } + + public override void SetShapeCollisionMargin(BulletShape shape, float margin) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + if (shapeu != null && shapeu.HasPhysicalShape) + BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin); + } + + public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale), + BSPhysicsShapeType.SHAPE_CAPSULE); + } + + public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + return new BulletShapeUnman( + BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree), + BSPhysicsShapeType.SHAPE_COMPOUND); + + } + + public override int GetNumberOfCompoundChildren(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + if (shapeu != null && shapeu.HasPhysicalShape) + return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr); + return 0; + } + + public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + BulletShapeUnman addShapeu = addShape as BulletShapeUnman; + BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot); + } + + public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); + } + + public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); + } + + public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman; + BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr); + } + + public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) + { + BulletShapeUnman shapeu = pShape as BulletShapeUnman; + BSAPICPP.UpdateChildTransform2(shapeu.ptr, childIndex, pos, rot, shouldRecalculateLocalAabb); + } + + public override void RecalculateCompoundShapeLocalAabb(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr); + } + + public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; + return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType); + } + + public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr); + } + + public override CollisionObjectTypes GetBodyType(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr); + } + + public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); + } + + public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot)); + } + + public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); + } + + public override void DestroyObject(BulletWorld world, BulletBody obj) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr); + } + + // ===================================================================================== + // Terrain creation and helper routines + public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin) + { + return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE); + } + + public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, + float scaleFactor, float collisionMargin) + { + return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin), + BSPhysicsShapeType.SHAPE_TERRAIN); + } + + // ===================================================================================== + // Constraint creation and helper routines + public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, + frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); + } + + public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 joinPoint, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, + joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); + } + + public override BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, + Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintFixed2(worldu.ptr, bodyu1.ptr, + frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies)); + } + + public override BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.Create6DofSpringConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, + frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); + } + + public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 pivotinA, Vector3 pivotinB, + Vector3 axisInA, Vector3 axisInB, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, + pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); + } + + public override BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.CreateSliderConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, + frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); + } + + public override BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool disableCollisionsBetweenLinkedBodies) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.CreateConeTwistConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, + frame2loc, frame2rot, disableCollisionsBetweenLinkedBodies)); + } + + public override BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 axisInA, Vector3 axisInB, + float ratio, bool disableCollisionsBetweenLinkedBodies) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.CreateGearConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, axisInA, axisInB, + ratio, disableCollisionsBetweenLinkedBodies)); + } + + public override BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 pivotInA, Vector3 pivotInB, + bool disableCollisionsBetweenLinkedBodies) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; + BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.CreatePoint2PointConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, pivotInA, pivotInB, + disableCollisionsBetweenLinkedBodies)); + } + + public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse); + } + + public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations); + } + + public override bool SetFrames(BulletConstraint constrain, + Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot); + } + + public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi); + } + + public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi); + } + + public override bool UseFrameOffset(BulletConstraint constrain, float enable) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable); + } + + public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce); + } + + public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold); + } + + public override bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.HingeSetLimits2(constrainu.ptr, low, high, softness, bias, relaxation); + } + + public override bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.ConstraintSpringEnable2(constrainu.ptr, index, numericTrueFalse); + } + + public override bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.ConstraintSpringSetEquilibriumPoint2(constrainu.ptr, index, equilibriumPoint); + } + + public override bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.ConstraintSpringSetStiffness2(constrainu.ptr, index, stiffnesss); + } + + public override bool SpringSetDamping(BulletConstraint constrain, int index, float damping) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.ConstraintSpringSetDamping2(constrainu.ptr, index, damping); + } + + public override bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SliderSetLimits2(constrainu.ptr, lowerUpper, linAng, val); + } + + public override bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SliderSet2(constrainu.ptr, softRestDamp, dirLimOrtho, linAng, val); + } + + public override bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SliderMotorEnable2(constrainu.ptr, linAng, numericTrueFalse); + } + + public override bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SliderMotor2(constrainu.ptr, forceVel, linAng, val); + } + + public override bool CalculateTransforms(BulletConstraint constrain) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.CalculateTransforms2(constrainu.ptr); + } + + public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis); + } + + public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr); + } + + // ===================================================================================== + // btCollisionWorld entries + public override void UpdateSingleAabb(BulletWorld world, BulletBody obj) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr); + } + + public override void UpdateAabbs(BulletWorld world) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.UpdateAabbs2(worldu.ptr); + } + + public override bool GetForceUpdateAllAabbs(BulletWorld world) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr); + } + + public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force); + } + + // ===================================================================================== + // btDynamicsWorld entries + public override bool AddObjectToWorld(BulletWorld world, BulletBody obj) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = obj as BulletBodyUnman; + + // Bullet resets several variables when an object is added to the world. + // Gravity is reset to world default depending on the static/dynamic + // type. Of course, the collision flags in the broadphase proxy are initialized to default. + Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr); + + bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr); + + if (ret) + { + BSAPICPP.SetGravity2(bodyu.ptr, origGrav); + obj.ApplyCollisionMask(world.physicsScene); + } + return ret; + } + + public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr); + } + + public override bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.ClearCollisionProxyCache2(worldu.ptr, bodyu.ptr); + } + + public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects); + } + + public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr); + } + // ===================================================================================== + // btCollisionObject entries + public override Vector3 GetAnisotripicFriction(BulletConstraint constrain) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr); + } + + public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict); + } + + public override bool HasAnisotripicFriction(BulletConstraint constrain) + { + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr); + } + + public override void SetContactProcessingThreshold(BulletBody obj, float val) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val); + } + + public override float GetContactProcessingThreshold(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr); + } + + public override bool IsStaticObject(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.IsStaticObject2(bodyu.ptr); + } + + public override bool IsKinematicObject(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.IsKinematicObject2(bodyu.ptr); + } + + public override bool IsStaticOrKinematicObject(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr); + } + + public override bool HasContactResponse(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.HasContactResponse2(bodyu.ptr); + } + + public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BulletShapeUnman shapeu = shape as BulletShapeUnman; + if (worldu != null && bodyu != null) + { + // Special case to allow the caller to zero out the reference to any physical shape + if (shapeu != null) + BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr); + else + BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero); + } + } + + public override BulletShape GetCollisionShape(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN); + } + + public override int GetActivationState(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetActivationState2(bodyu.ptr); + } + + public override void SetActivationState(BulletBody obj, int state) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetActivationState2(bodyu.ptr, state); + } + + public override void SetDeactivationTime(BulletBody obj, float dtime) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime); + } + + public override float GetDeactivationTime(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetDeactivationTime2(bodyu.ptr); + } + + public override void ForceActivationState(BulletBody obj, ActivationState state) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ForceActivationState2(bodyu.ptr, state); + } + + public override void Activate(BulletBody obj, bool forceActivation) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.Activate2(bodyu.ptr, forceActivation); + } + + public override bool IsActive(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.IsActive2(bodyu.ptr); + } + + public override void SetRestitution(BulletBody obj, float val) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetRestitution2(bodyu.ptr, val); + } + + public override float GetRestitution(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetRestitution2(bodyu.ptr); + } + + public override void SetFriction(BulletBody obj, float val) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetFriction2(bodyu.ptr, val); + } + + public override float GetFriction(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetFriction2(bodyu.ptr); + } + + public override Vector3 GetPosition(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetPosition2(bodyu.ptr); + } + + public override Quaternion GetOrientation(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetOrientation2(bodyu.ptr); + } + + public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation); + } + + /* + public override IntPtr GetBroadphaseHandle(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr); + } + + public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetUserPointer2(bodyu.ptr, handle); + } + */ + + public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel); + } + + public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel); + } + + public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel); + } + + public override float GetHitFraction(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetHitFraction2(bodyu.ptr); + } + + public override void SetHitFraction(BulletBody obj, float val) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetHitFraction2(bodyu.ptr, val); + } + + public override CollisionFlags GetCollisionFlags(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetCollisionFlags2(bodyu.ptr); + } + + public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags); + } + + public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags); + } + + public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags); + } + + public override float GetCcdMotionThreshold(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr); + } + + + public override void SetCcdMotionThreshold(BulletBody obj, float val) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val); + } + + public override float GetCcdSweptSphereRadius(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr); + } + + public override void SetCcdSweptSphereRadius(BulletBody obj, float val) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val); + } + + public override IntPtr GetUserPointer(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetUserPointer2(bodyu.ptr); + } + + public override void SetUserPointer(BulletBody obj, IntPtr val) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetUserPointer2(bodyu.ptr, val); + } + + // ===================================================================================== + // btRigidBody entries + public override void ApplyGravity(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyGravity2(bodyu.ptr); + } + + public override void SetGravity(BulletBody obj, Vector3 val) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetGravity2(bodyu.ptr, val); + } + + public override Vector3 GetGravity(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetGravity2(bodyu.ptr); + } + + public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping); + } + + public override void SetLinearDamping(BulletBody obj, float lin_damping) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping); + } + + public override void SetAngularDamping(BulletBody obj, float ang_damping) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping); + } + + public override float GetLinearDamping(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetLinearDamping2(bodyu.ptr); + } + + public override float GetAngularDamping(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetAngularDamping2(bodyu.ptr); + } + + public override float GetLinearSleepingThreshold(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr); + } + + public override void ApplyDamping(BulletBody obj, float timeStep) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep); + } + + public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia); + } + + public override Vector3 GetLinearFactor(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetLinearFactor2(bodyu.ptr); + } + + public override void SetLinearFactor(BulletBody obj, Vector3 factor) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetLinearFactor2(bodyu.ptr, factor); + } + + public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot); + } + + // Add a force to the object as if its mass is one. + // Deep down in Bullet: m_totalForce += force*m_linearFactor; + public override void ApplyCentralForce(BulletBody obj, Vector3 force) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyCentralForce2(bodyu.ptr, force); + } + + // Set the force being applied to the object as if its mass is one. + public override void SetObjectForce(BulletBody obj, Vector3 force) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetObjectForce2(bodyu.ptr, force); + } + + public override Vector3 GetTotalForce(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetTotalForce2(bodyu.ptr); + } + + public override Vector3 GetTotalTorque(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetTotalTorque2(bodyu.ptr); + } + + public override Vector3 GetInvInertiaDiagLocal(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr); + } + + public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert); + } + + public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold); + } + + // Deep down in Bullet: m_totalTorque += torque*m_angularFactor; + public override void ApplyTorque(BulletBody obj, Vector3 torque) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyTorque2(bodyu.ptr, torque); + } + + // Apply force at the given point. Will add torque to the object. + // Deep down in Bullet: applyCentralForce(force); + // applyTorque(rel_pos.cross(force*m_linearFactor)); + public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyForce2(bodyu.ptr, force, pos); + } + + // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. + // Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass; + public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp); + } + + // Apply impulse to the object's torque. Force is scaled by object's mass. + // Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor; + public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp); + } + + // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. + // Deep down in Bullet: applyCentralImpulse(impulse); + // applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor)); + public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos); + } + + public override void ClearForces(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ClearForces2(bodyu.ptr); + } + + public override void ClearAllForces(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.ClearAllForces2(bodyu.ptr); + } + + public override void UpdateInertiaTensor(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.UpdateInertiaTensor2(bodyu.ptr); + } + + public override Vector3 GetLinearVelocity(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetLinearVelocity2(bodyu.ptr); + } + + public override Vector3 GetAngularVelocity(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetAngularVelocity2(bodyu.ptr); + } + + public override void SetLinearVelocity(BulletBody obj, Vector3 vel) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel); + } + + public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity); + } + + public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos); + } + + public override void Translate(BulletBody obj, Vector3 trans) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.Translate2(bodyu.ptr, trans); + } + + public override void UpdateDeactivation(BulletBody obj, float timeStep) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep); + } + + public override bool WantsSleeping(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.WantsSleeping2(bodyu.ptr); + } + + public override void SetAngularFactor(BulletBody obj, float factor) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetAngularFactor2(bodyu.ptr, factor); + } + + public override void SetAngularFactorV(BulletBody obj, Vector3 factor) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor); + } + + public override Vector3 GetAngularFactor(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetAngularFactor2(bodyu.ptr); + } + + public override bool IsInWorld(BulletWorld world, BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.IsInWorld2(bodyu.ptr); + } + + public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr); + } + + public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr); + } + + public override BulletConstraint GetConstraintRef(BulletBody obj, int index) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index)); + } + + public override int GetNumConstraintRefs(BulletBody obj) + { + BulletBodyUnman bodyu = obj as BulletBodyUnman; + return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr); + } + + public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask) + { + BulletBodyUnman bodyu = body as BulletBodyUnman; + return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask); + } + + // ===================================================================================== + // btCollisionShape entries + + public override float GetAngularMotionDisc(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr); + } + + public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor); + } + + public override bool IsPolyhedral(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsPolyhedral2(shapeu.ptr); + } + + public override bool IsConvex2d(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsConvex2d2(shapeu.ptr); + } + + public override bool IsConvex(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsConvex2(shapeu.ptr); + } + + public override bool IsNonMoving(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsNonMoving2(shapeu.ptr); + } + + public override bool IsConcave(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsConcave2(shapeu.ptr); + } + + public override bool IsCompound(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsCompound2(shapeu.ptr); + } + + public override bool IsSoftBody(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsSoftBody2(shapeu.ptr); + } + + public override bool IsInfinite(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.IsInfinite2(shapeu.ptr); + } + + public override void SetLocalScaling(BulletShape shape, Vector3 scale) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + BSAPICPP.SetLocalScaling2(shapeu.ptr, scale); + } + + public override Vector3 GetLocalScaling(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.GetLocalScaling2(shapeu.ptr); + } + + public override Vector3 CalculateLocalInertia(BulletShape shape, float mass) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass); + } + + public override int GetShapeType(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.GetShapeType2(shapeu.ptr); + } + + public override void SetMargin(BulletShape shape, float val) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + BSAPICPP.SetMargin2(shapeu.ptr, val); + } + + public override float GetMargin(BulletShape shape) + { + BulletShapeUnman shapeu = shape as BulletShapeUnman; + return BSAPICPP.GetMargin2(shapeu.ptr); + } + + // ===================================================================================== + // Raycast + public override SweepHit ConvexSweepTest2(BulletWorld world, BulletBody sweepObject, Vector3 from, Vector3 to, float margin) { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = sweepObject as BulletBodyUnman; + return BSAPICPP.ConvexSweepTest2(worldu.ptr, bodyu.ptr, from, to, margin); + } + + public override RaycastHit RayTest2(BulletWorld world, Vector3 from, Vector3 to, uint filterGroup, uint filterMask) { + BulletWorldUnman worldu = world as BulletWorldUnman; + return BSAPICPP.RayTest2(worldu.ptr, from, to, filterGroup, filterMask); + } + + // ===================================================================================== + // Debugging + public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletBodyUnman bodyu = collisionObject as BulletBodyUnman; + BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr); + } + + public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletShapeUnman shapeu = collisionShape as BulletShapeUnman; + BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr); + } + + public override void DumpConstraint(BulletWorld world, BulletConstraint constrain) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; + BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr); + } + + public override void DumpActivationInfo(BulletWorld world) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.DumpActivationInfo2(worldu.ptr); + } + + public override void DumpAllInfo(BulletWorld world) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.DumpAllInfo2(worldu.ptr); + } + + public override void DumpPhysicsStatistics(BulletWorld world) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.DumpPhysicsStatistics2(worldu.ptr); + } + public override void ResetBroadphasePool(BulletWorld world) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.ResetBroadphasePool(worldu.ptr); + } + public override void ResetConstraintSolver(BulletWorld world) + { + BulletWorldUnman worldu = world as BulletWorldUnman; + BSAPICPP.ResetConstraintSolver(worldu.ptr); + } + + // ===================================================================================== + // ===================================================================================== + // ===================================================================================== + // ===================================================================================== + // ===================================================================================== + // The actual interface to the unmanaged code + static class BSAPICPP + { + // =============================================================================== + // Link back to the managed code for outputting log messages + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); + + // =============================================================================== + // Initialization and simulation + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, + int maxCollisions, IntPtr collisionArray, + int maxUpdates, IntPtr updateArray, + DebugLogCallback logRoutine); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, + out int updatedEntityCount, out int collidersCount); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void Shutdown2(IntPtr sim); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool PushUpdate2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); + + // ===================================================================================== + // Mesh, hull, shape and body creation helper routines + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateMeshShape2(IntPtr world, + int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, + int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateGImpactShape2(IntPtr world, + int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, + int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateHullShape2(IntPtr world, + int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateConvexHullShape2(IntPtr world, + int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, + int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsNativeShape2(IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetShapeCollisionMargin(IntPtr shape, float margin); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern int GetNumberOfCompoundChildren2(IntPtr cShape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern int GetBodyType2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void DestroyObject2(IntPtr sim, IntPtr obj); + + // ===================================================================================== + // Terrain creation and helper routines + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, + [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, + float scaleFactor, float collisionMargin); + + // ===================================================================================== + // Constraint creation and helper routines + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 joinPoint, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr Create6DofConstraintFixed2(IntPtr world, IntPtr obj1, + Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr Create6DofSpringConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 pivotinA, Vector3 pivotinB, + Vector3 axisInA, Vector3 axisInB, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateSliderConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateConeTwistConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool disableCollisionsBetweenLinkedBodies); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreateGearConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 axisInA, Vector3 axisInB, + float ratio, bool disableCollisionsBetweenLinkedBodies); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr CreatePoint2PointConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, + Vector3 pivotInA, Vector3 pivotInB, + bool disableCollisionsBetweenLinkedBodies); + + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool SetFrames2(IntPtr constrain, + Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool UseFrameOffset2(IntPtr constrain, float enable); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool HingeSetLimits2(IntPtr constrain, float low, float high, float softness, float bias, float relaxation); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool ConstraintSpringEnable2(IntPtr constrain, int index, float numericTrueFalse); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool ConstraintSpringSetEquilibriumPoint2(IntPtr constrain, int index, float equilibriumPoint); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool ConstraintSpringSetStiffness2(IntPtr constrain, int index, float stiffness); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool ConstraintSpringSetDamping2(IntPtr constrain, int index, float damping); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool SliderSetLimits2(IntPtr constrain, int lowerUpper, int linAng, float val); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool SliderSet2(IntPtr constrain, int softRestDamp, int dirLimOrtho, int linAng, float val); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool SliderMotorEnable2(IntPtr constrain, int linAng, float numericTrueFalse); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool SliderMotor2(IntPtr constrain, int forceVel, int linAng, float val); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool CalculateTransforms2(IntPtr constrain); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); + + // ===================================================================================== + // btCollisionWorld entries + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void UpdateAabbs2(IntPtr world); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool GetForceUpdateAllAabbs2(IntPtr world); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force); + + // ===================================================================================== + // btDynamicsWorld entries + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool ClearCollisionProxyCache2(IntPtr world, IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain); + // ===================================================================================== + // btCollisionObject entries + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool HasAnisotripicFriction2(IntPtr constrain); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetContactProcessingThreshold2(IntPtr obj, float val); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetContactProcessingThreshold2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsStaticObject2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsKinematicObject2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsStaticOrKinematicObject2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool HasContactResponse2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr GetCollisionShape2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern int GetActivationState2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetActivationState2(IntPtr obj, int state); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetDeactivationTime2(IntPtr obj, float dtime); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetDeactivationTime2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void ForceActivationState2(IntPtr obj, ActivationState state); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void Activate2(IntPtr obj, bool forceActivation); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsActive2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetRestitution2(IntPtr obj, float val); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetRestitution2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetFriction2(IntPtr obj, float val); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetFriction2(IntPtr obj); + + /* Haven't defined the type 'Transform' + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Transform GetWorldTransform2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void setWorldTransform2(IntPtr obj, Transform trans); + */ + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 GetPosition2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Quaternion GetOrientation2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr GetBroadphaseHandle2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle); + + /* + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Transform GetInterpolationWorldTransform2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans); + */ + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetHitFraction2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetHitFraction2(IntPtr obj, float val); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetCcdMotionThreshold2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetCcdSweptSphereRadius2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr GetUserPointer2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetUserPointer2(IntPtr obj, IntPtr val); + + // ===================================================================================== + // btRigidBody entries + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void ApplyGravity2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetGravity2(IntPtr obj, Vector3 val); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 GetGravity2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetLinearDamping2(IntPtr obj, float lin_damping); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetAngularDamping2(IntPtr obj, float ang_damping); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetLinearDamping2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetAngularDamping2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetLinearSleepingThreshold2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetAngularSleepingThreshold2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void ApplyDamping2(IntPtr obj, float timeStep); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 GetLinearFactor2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor); + + /* + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans); + */ + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot); + + // Add a force to the object as if its mass is one. + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force); + + // Set the force being applied to the object as if its mass is one. + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetObjectForce2(IntPtr obj, Vector3 force); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 GetTotalForce2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 GetTotalTorque2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void ApplyTorque2(IntPtr obj, Vector3 torque); + + // Apply force at the given point. Will add torque to the object. + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos); + + // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp); + + // Apply impulse to the object's torque. Force is scaled by object's mass. + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp); + + // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void ClearForces2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void ClearAllForces2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void UpdateInertiaTensor2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj); + + /* + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Transform GetCenterOfMassTransform2(IntPtr obj); + */ + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 GetLinearVelocity2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 GetAngularVelocity2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void Translate2(IntPtr obj, Vector3 trans); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void UpdateDeactivation2(IntPtr obj, float timeStep); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool WantsSleeping2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetAngularFactor2(IntPtr obj, float factor); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 GetAngularFactor2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsInWorld2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern int GetNumConstraintRefs2(IntPtr obj); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask); + + // ===================================================================================== + // btCollisionShape entries + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetAngularMotionDisc2(IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsPolyhedral2(IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsConvex2d2(IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsConvex2(IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsNonMoving2(IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsConcave2(IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsCompound2(IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsSoftBody2(IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern bool IsInfinite2(IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 GetLocalScaling2(IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern int GetShapeType2(IntPtr shape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void SetMargin2(IntPtr shape, float val); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern float GetMargin2(IntPtr shape); + + + // ===================================================================================== + // Raycast + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern SweepHit ConvexSweepTest2(IntPtr sim, IntPtr obj, Vector3 from, Vector3 to, float margin); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern RaycastHit RayTest2(IntPtr sim, Vector3 from, Vector3 to, uint filterGroup, uint filterMask); + + // ===================================================================================== + // Debugging + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void DumpActivationInfo2(IntPtr sim); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void DumpAllInfo2(IntPtr sim); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void DumpPhysicsStatistics2(IntPtr sim); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void ResetBroadphasePool(IntPtr sim); + + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] + public static extern void ResetConstraintSolver(IntPtr sim); + + } } } - -private sealed class BulletBodyUnman : BulletBody -{ - public IntPtr ptr; - public BulletBodyUnman(uint id, IntPtr xx) - : base(id) - { - ptr = xx; - } - public override bool HasPhysicalBody - { - get { return ptr != IntPtr.Zero; } - } - public override void Clear() - { - ptr = IntPtr.Zero; - } - public override string AddrString - { - get { return ptr.ToString("X"); } - } -} - -private sealed class BulletShapeUnman : BulletShape -{ - public IntPtr ptr; - public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ) - : base() - { - ptr = xx; - shapeType = typ; - } - public override bool HasPhysicalShape - { - get { return ptr != IntPtr.Zero; } - } - public override void Clear() - { - ptr = IntPtr.Zero; - } - public override BulletShape Clone() - { - return new BulletShapeUnman(ptr, shapeType); - } - public override bool ReferenceSame(BulletShape other) - { - BulletShapeUnman otheru = other as BulletShapeUnman; - return (otheru != null) && (this.ptr == otheru.ptr); - - } - public override string AddrString - { - get { return ptr.ToString("X"); } - } -} -private sealed class BulletConstraintUnman : BulletConstraint -{ - public BulletConstraintUnman(IntPtr xx) : base() - { - ptr = xx; - } - public IntPtr ptr; - - public override void Clear() - { - ptr = IntPtr.Zero; - } - public override bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } } - - // Used for log messages for a unique display of the memory/object allocated to this instance - public override string AddrString - { - get { return ptr.ToString("X"); } - } -} - -// We pin the memory passed between the managed and unmanaged code. -GCHandle m_paramsHandle; -private GCHandle m_collisionArrayPinnedHandle; -private GCHandle m_updateArrayPinnedHandle; - -// Handle to the callback used by the unmanaged code to call into the managed code. -// Used for debug logging. -// Need to store the handle in a persistant variable so it won't be freed. -private BSAPICPP.DebugLogCallback m_DebugLogCallbackHandle; - -private BSScene PhysicsScene { get; set; } - -public override string BulletEngineName { get { return "BulletUnmanaged"; } } -public override string BulletEngineVersion { get; protected set; } - -public BSAPIUnman(string paramName, BSScene physScene) -{ - PhysicsScene = physScene; - - // Do something fancy with the paramName to get the right DLL implementation - // like "Bullet-2.80-OpenCL-Intel" loading the version for Intel based OpenCL implementation, etc. - if (Util.IsWindows()) - Util.LoadArchSpecificWindowsDll("BulletSim.dll"); - // If not Windows, loading is performed by the - // Mono loader as specified in - // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". -} - -// Initialization and simulation -public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, - int maxCollisions, ref CollisionDesc[] collisionArray, - int maxUpdates, ref EntityProperties[] updateArray - ) -{ - // Pin down the memory that will be used to pass object collisions and updates back from unmanaged code - m_paramsHandle = GCHandle.Alloc(parms, GCHandleType.Pinned); - m_collisionArrayPinnedHandle = GCHandle.Alloc(collisionArray, GCHandleType.Pinned); - m_updateArrayPinnedHandle = GCHandle.Alloc(updateArray, GCHandleType.Pinned); - - // If Debug logging level, enable logging from the unmanaged code - m_DebugLogCallbackHandle = null; - if (BSScene.m_log.IsDebugEnabled && PhysicsScene.PhysicsLogging.Enabled) - { - BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader); - if (PhysicsScene.PhysicsLogging.Enabled) - // The handle is saved in a variable to make sure it doesn't get freed after this call - m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLoggerPhysLog); - else - m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLogger); - } - - // Get the version of the DLL - // TODO: this doesn't work yet. Something wrong with marshaling the returned string. - // BulletEngineVersion = BulletSimAPI.GetVersion2(); - BulletEngineVersion = ""; - - // Call the unmanaged code with the buffers and other information - return new BulletWorldUnman(0, PhysicsScene, BSAPICPP.Initialize2(maxPosition, m_paramsHandle.AddrOfPinnedObject(), - maxCollisions, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), - maxUpdates, m_updateArrayPinnedHandle.AddrOfPinnedObject(), - m_DebugLogCallbackHandle)); - -} - -// Called directly from unmanaged code so don't do much -private void BulletLogger(string msg) -{ - BSScene.m_log.Debug("[BULLETS UNMANAGED]:" + msg); -} - -// Called directly from unmanaged code so don't do much -private void BulletLoggerPhysLog(string msg) -{ - PhysicsScene.DetailLog("[BULLETS UNMANAGED]:" + msg); -} - -public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, - out int updatedEntityCount, out int collidersCount) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount); -} - -public override void Shutdown(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.Shutdown2(worldu.ptr); - - if (m_paramsHandle.IsAllocated) - { - m_paramsHandle.Free(); - } - if (m_collisionArrayPinnedHandle.IsAllocated) - { - m_collisionArrayPinnedHandle.Free(); - } - if (m_updateArrayPinnedHandle.IsAllocated) - { - m_updateArrayPinnedHandle.Free(); - } -} - -public override bool PushUpdate(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.PushUpdate2(bodyu.ptr); -} - -public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return BSAPICPP.UpdateParameter2(worldu.ptr, localID, parm, value); -} - -// ===================================================================================== -// Mesh, hull, shape and body creation helper routines -public override BulletShape CreateMeshShape(BulletWorld world, - int indicesCount, int[] indices, - int verticesCount, float[] vertices) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return new BulletShapeUnman( - BSAPICPP.CreateMeshShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), - BSPhysicsShapeType.SHAPE_MESH); -} - -public override BulletShape CreateGImpactShape(BulletWorld world, - int indicesCount, int[] indices, - int verticesCount, float[] vertices) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return new BulletShapeUnman( - BSAPICPP.CreateGImpactShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), - BSPhysicsShapeType.SHAPE_GIMPACT); -} - -public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return new BulletShapeUnman( - BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls), - BSPhysicsShapeType.SHAPE_HULL); -} - -public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletShapeUnman shapeu = meshShape as BulletShapeUnman; - return new BulletShapeUnman( - BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr, parms), - BSPhysicsShapeType.SHAPE_HULL); -} - -public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletShapeUnman shapeu = meshShape as BulletShapeUnman; - return new BulletShapeUnman( - BSAPICPP.BuildConvexHullShapeFromMesh2(worldu.ptr, shapeu.ptr), - BSPhysicsShapeType.SHAPE_CONVEXHULL); -} - -public override BulletShape CreateConvexHullShape(BulletWorld world, - int indicesCount, int[] indices, - int verticesCount, float[] vertices) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return new BulletShapeUnman( - BSAPICPP.CreateConvexHullShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices), - BSPhysicsShapeType.SHAPE_CONVEXHULL); -} - -public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type); -} - -public override bool IsNativeShape(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - if (shapeu != null && shapeu.HasPhysicalShape) - return BSAPICPP.IsNativeShape2(shapeu.ptr); - return false; -} - -public override void SetShapeCollisionMargin(BulletShape shape, float margin) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - if (shapeu != null && shapeu.HasPhysicalShape) - BSAPICPP.SetShapeCollisionMargin(shapeu.ptr, margin); -} - -public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return new BulletShapeUnman( - BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale), - BSPhysicsShapeType.SHAPE_CAPSULE); -} - -public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return new BulletShapeUnman( - BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree), - BSPhysicsShapeType.SHAPE_COMPOUND); - -} - -public override int GetNumberOfCompoundChildren(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - if (shapeu != null && shapeu.HasPhysicalShape) - return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr); - return 0; -} - -public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - BulletShapeUnman addShapeu = addShape as BulletShapeUnman; - BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot); -} - -public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); -} - -public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN); -} - -public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman; - BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr); -} - -public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) -{ - BulletShapeUnman shapeu = pShape as BulletShapeUnman; - BSAPICPP.UpdateChildTransform2(shapeu.ptr, childIndex, pos, rot, shouldRecalculateLocalAabb); -} - -public override void RecalculateCompoundShapeLocalAabb(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr); -} - -public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman; - return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.shapeType); -} - -public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr); -} - -public override CollisionObjectTypes GetBodyType(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr); -} - -public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); -} - -public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot)); -} - -public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot)); -} - -public override void DestroyObject(BulletWorld world, BulletBody obj) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr); -} - -// ===================================================================================== -// Terrain creation and helper routines -public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin) -{ - return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE); -} - -public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, - float scaleFactor, float collisionMargin) -{ - return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin), - BSPhysicsShapeType.SHAPE_TERRAIN); -} - -// ===================================================================================== -// Constraint creation and helper routines -public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frame1loc, Quaternion frame1rot, - Vector3 frame2loc, Quaternion frame2rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; - BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, - frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); -} - -public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 joinPoint, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; - BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, - joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); -} - -public override BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, - Vector3 frameInBloc, Quaternion frameInBrot, - bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintFixed2(worldu.ptr, bodyu1.ptr, - frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies)); -} - -public override BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frame1loc, Quaternion frame1rot, - Vector3 frame2loc, Quaternion frame2rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; - BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.Create6DofSpringConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, - frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); -} - -public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 pivotinA, Vector3 pivotinB, - Vector3 axisInA, Vector3 axisInB, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; - BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, - pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); -} - -public override BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frame1loc, Quaternion frame1rot, - Vector3 frame2loc, Quaternion frame2rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; - BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.CreateSliderConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, - frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); -} - -public override BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frame1loc, Quaternion frame1rot, - Vector3 frame2loc, Quaternion frame2rot, - bool disableCollisionsBetweenLinkedBodies) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; - BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.CreateConeTwistConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot, - frame2loc, frame2rot, disableCollisionsBetweenLinkedBodies)); -} - -public override BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 axisInA, Vector3 axisInB, - float ratio, bool disableCollisionsBetweenLinkedBodies) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; - BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.CreateGearConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, axisInA, axisInB, - ratio, disableCollisionsBetweenLinkedBodies)); -} - -public override BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 pivotInA, Vector3 pivotInB, - bool disableCollisionsBetweenLinkedBodies) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman; - BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.CreatePoint2PointConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, pivotInA, pivotInB, - disableCollisionsBetweenLinkedBodies)); -} - -public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse); -} - -public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations); -} - -public override bool SetFrames(BulletConstraint constrain, - Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot); -} - -public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi); -} - -public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi); -} - -public override bool UseFrameOffset(BulletConstraint constrain, float enable) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable); -} - -public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce); -} - -public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold); -} - -public override bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.HingeSetLimits2(constrainu.ptr, low, high, softness, bias, relaxation); -} - -public override bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.ConstraintSpringEnable2(constrainu.ptr, index, numericTrueFalse); -} - -public override bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.ConstraintSpringSetEquilibriumPoint2(constrainu.ptr, index, equilibriumPoint); -} - -public override bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.ConstraintSpringSetStiffness2(constrainu.ptr, index, stiffnesss); -} - -public override bool SpringSetDamping(BulletConstraint constrain, int index, float damping) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.ConstraintSpringSetDamping2(constrainu.ptr, index, damping); -} - -public override bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SliderSetLimits2(constrainu.ptr, lowerUpper, linAng, val); -} - -public override bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SliderSet2(constrainu.ptr, softRestDamp, dirLimOrtho, linAng, val); -} - -public override bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SliderMotorEnable2(constrainu.ptr, linAng, numericTrueFalse); -} - -public override bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SliderMotor2(constrainu.ptr, forceVel, linAng, val); -} - -public override bool CalculateTransforms(BulletConstraint constrain) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.CalculateTransforms2(constrainu.ptr); -} - -public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis); -} - -public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr); -} - -// ===================================================================================== -// btCollisionWorld entries -public override void UpdateSingleAabb(BulletWorld world, BulletBody obj) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr); -} - -public override void UpdateAabbs(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.UpdateAabbs2(worldu.ptr); -} - -public override bool GetForceUpdateAllAabbs(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr); -} - -public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force); -} - -// ===================================================================================== -// btDynamicsWorld entries -public override bool AddObjectToWorld(BulletWorld world, BulletBody obj) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = obj as BulletBodyUnman; - - // Bullet resets several variables when an object is added to the world. - // Gravity is reset to world default depending on the static/dynamic - // type. Of course, the collision flags in the broadphase proxy are initialized to default. - Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr); - - bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr); - - if (ret) - { - BSAPICPP.SetGravity2(bodyu.ptr, origGrav); - obj.ApplyCollisionMask(world.physicsScene); - } - return ret; -} - -public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr); -} - -public override bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.ClearCollisionProxyCache2(worldu.ptr, bodyu.ptr); -} - -public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects); -} - -public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr); -} -// ===================================================================================== -// btCollisionObject entries -public override Vector3 GetAnisotripicFriction(BulletConstraint constrain) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr); -} - -public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict); -} - -public override bool HasAnisotripicFriction(BulletConstraint constrain) -{ - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr); -} - -public override void SetContactProcessingThreshold(BulletBody obj, float val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val); -} - -public override float GetContactProcessingThreshold(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr); -} - -public override bool IsStaticObject(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.IsStaticObject2(bodyu.ptr); -} - -public override bool IsKinematicObject(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.IsKinematicObject2(bodyu.ptr); -} - -public override bool IsStaticOrKinematicObject(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr); -} - -public override bool HasContactResponse(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.HasContactResponse2(bodyu.ptr); -} - -public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BulletShapeUnman shapeu = shape as BulletShapeUnman; - if (worldu != null && bodyu != null) - { - // Special case to allow the caller to zero out the reference to any physical shape - if (shapeu != null) - BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr); - else - BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero); - } -} - -public override BulletShape GetCollisionShape(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN); -} - -public override int GetActivationState(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetActivationState2(bodyu.ptr); -} - -public override void SetActivationState(BulletBody obj, int state) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetActivationState2(bodyu.ptr, state); -} - -public override void SetDeactivationTime(BulletBody obj, float dtime) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime); -} - -public override float GetDeactivationTime(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetDeactivationTime2(bodyu.ptr); -} - -public override void ForceActivationState(BulletBody obj, ActivationState state) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ForceActivationState2(bodyu.ptr, state); -} - -public override void Activate(BulletBody obj, bool forceActivation) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.Activate2(bodyu.ptr, forceActivation); -} - -public override bool IsActive(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.IsActive2(bodyu.ptr); -} - -public override void SetRestitution(BulletBody obj, float val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetRestitution2(bodyu.ptr, val); -} - -public override float GetRestitution(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetRestitution2(bodyu.ptr); -} - -public override void SetFriction(BulletBody obj, float val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetFriction2(bodyu.ptr, val); -} - -public override float GetFriction(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetFriction2(bodyu.ptr); -} - -public override Vector3 GetPosition(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetPosition2(bodyu.ptr); -} - -public override Quaternion GetOrientation(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetOrientation2(bodyu.ptr); -} - -public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation); -} - - /* -public override IntPtr GetBroadphaseHandle(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr); -} - -public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetUserPointer2(bodyu.ptr, handle); -} - */ - -public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel); -} - -public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel); -} - -public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel); -} - -public override float GetHitFraction(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetHitFraction2(bodyu.ptr); -} - -public override void SetHitFraction(BulletBody obj, float val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetHitFraction2(bodyu.ptr, val); -} - -public override CollisionFlags GetCollisionFlags(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetCollisionFlags2(bodyu.ptr); -} - -public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags); -} - -public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags); -} - -public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags); -} - -public override float GetCcdMotionThreshold(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr); -} - - -public override void SetCcdMotionThreshold(BulletBody obj, float val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val); -} - -public override float GetCcdSweptSphereRadius(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr); -} - -public override void SetCcdSweptSphereRadius(BulletBody obj, float val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val); -} - -public override IntPtr GetUserPointer(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetUserPointer2(bodyu.ptr); -} - -public override void SetUserPointer(BulletBody obj, IntPtr val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetUserPointer2(bodyu.ptr, val); -} - -// ===================================================================================== -// btRigidBody entries -public override void ApplyGravity(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyGravity2(bodyu.ptr); -} - -public override void SetGravity(BulletBody obj, Vector3 val) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetGravity2(bodyu.ptr, val); -} - -public override Vector3 GetGravity(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetGravity2(bodyu.ptr); -} - -public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping); -} - -public override void SetLinearDamping(BulletBody obj, float lin_damping) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping); -} - -public override void SetAngularDamping(BulletBody obj, float ang_damping) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping); -} - -public override float GetLinearDamping(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetLinearDamping2(bodyu.ptr); -} - -public override float GetAngularDamping(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetAngularDamping2(bodyu.ptr); -} - -public override float GetLinearSleepingThreshold(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr); -} - -public override void ApplyDamping(BulletBody obj, float timeStep) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep); -} - -public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia); -} - -public override Vector3 GetLinearFactor(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetLinearFactor2(bodyu.ptr); -} - -public override void SetLinearFactor(BulletBody obj, Vector3 factor) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetLinearFactor2(bodyu.ptr, factor); -} - -public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot); -} - -// Add a force to the object as if its mass is one. -// Deep down in Bullet: m_totalForce += force*m_linearFactor; -public override void ApplyCentralForce(BulletBody obj, Vector3 force) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyCentralForce2(bodyu.ptr, force); -} - -// Set the force being applied to the object as if its mass is one. -public override void SetObjectForce(BulletBody obj, Vector3 force) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetObjectForce2(bodyu.ptr, force); -} - -public override Vector3 GetTotalForce(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetTotalForce2(bodyu.ptr); -} - -public override Vector3 GetTotalTorque(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetTotalTorque2(bodyu.ptr); -} - -public override Vector3 GetInvInertiaDiagLocal(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr); -} - -public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert); -} - -public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold); -} - -// Deep down in Bullet: m_totalTorque += torque*m_angularFactor; -public override void ApplyTorque(BulletBody obj, Vector3 torque) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyTorque2(bodyu.ptr, torque); -} - -// Apply force at the given point. Will add torque to the object. -// Deep down in Bullet: applyCentralForce(force); -// applyTorque(rel_pos.cross(force*m_linearFactor)); -public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyForce2(bodyu.ptr, force, pos); -} - -// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. -// Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass; -public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp); -} - -// Apply impulse to the object's torque. Force is scaled by object's mass. -// Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor; -public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp); -} - -// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. -// Deep down in Bullet: applyCentralImpulse(impulse); -// applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor)); -public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos); -} - -public override void ClearForces(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ClearForces2(bodyu.ptr); -} - -public override void ClearAllForces(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.ClearAllForces2(bodyu.ptr); -} - -public override void UpdateInertiaTensor(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.UpdateInertiaTensor2(bodyu.ptr); -} - -public override Vector3 GetLinearVelocity(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetLinearVelocity2(bodyu.ptr); -} - -public override Vector3 GetAngularVelocity(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetAngularVelocity2(bodyu.ptr); -} - -public override void SetLinearVelocity(BulletBody obj, Vector3 vel) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel); -} - -public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity); -} - -public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos); -} - -public override void Translate(BulletBody obj, Vector3 trans) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.Translate2(bodyu.ptr, trans); -} - -public override void UpdateDeactivation(BulletBody obj, float timeStep) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep); -} - -public override bool WantsSleeping(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.WantsSleeping2(bodyu.ptr); -} - -public override void SetAngularFactor(BulletBody obj, float factor) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetAngularFactor2(bodyu.ptr, factor); -} - -public override void SetAngularFactorV(BulletBody obj, Vector3 factor) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor); -} - -public override Vector3 GetAngularFactor(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetAngularFactor2(bodyu.ptr); -} - -public override bool IsInWorld(BulletWorld world, BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.IsInWorld2(bodyu.ptr); -} - -public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr); -} - -public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr); -} - -public override BulletConstraint GetConstraintRef(BulletBody obj, int index) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index)); -} - -public override int GetNumConstraintRefs(BulletBody obj) -{ - BulletBodyUnman bodyu = obj as BulletBodyUnman; - return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr); -} - -public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask) -{ - BulletBodyUnman bodyu = body as BulletBodyUnman; - return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask); -} - -// ===================================================================================== -// btCollisionShape entries - -public override float GetAngularMotionDisc(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr); -} - -public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor); -} - -public override bool IsPolyhedral(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsPolyhedral2(shapeu.ptr); -} - -public override bool IsConvex2d(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsConvex2d2(shapeu.ptr); -} - -public override bool IsConvex(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsConvex2(shapeu.ptr); -} - -public override bool IsNonMoving(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsNonMoving2(shapeu.ptr); -} - -public override bool IsConcave(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsConcave2(shapeu.ptr); -} - -public override bool IsCompound(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsCompound2(shapeu.ptr); -} - -public override bool IsSoftBody(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsSoftBody2(shapeu.ptr); -} - -public override bool IsInfinite(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.IsInfinite2(shapeu.ptr); -} - -public override void SetLocalScaling(BulletShape shape, Vector3 scale) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - BSAPICPP.SetLocalScaling2(shapeu.ptr, scale); -} - -public override Vector3 GetLocalScaling(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.GetLocalScaling2(shapeu.ptr); -} - -public override Vector3 CalculateLocalInertia(BulletShape shape, float mass) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass); -} - -public override int GetShapeType(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.GetShapeType2(shapeu.ptr); -} - -public override void SetMargin(BulletShape shape, float val) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - BSAPICPP.SetMargin2(shapeu.ptr, val); -} - -public override float GetMargin(BulletShape shape) -{ - BulletShapeUnman shapeu = shape as BulletShapeUnman; - return BSAPICPP.GetMargin2(shapeu.ptr); -} - -// ===================================================================================== -// Raycast -public override SweepHit ConvexSweepTest2(BulletWorld world, BulletBody sweepObject, Vector3 from, Vector3 to, float margin) { - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = sweepObject as BulletBodyUnman; - return BSAPICPP.ConvexSweepTest2(worldu.ptr, bodyu.ptr, from, to, margin); -} - -public override RaycastHit RayTest2(BulletWorld world, Vector3 from, Vector3 to, uint filterGroup, uint filterMask) { - BulletWorldUnman worldu = world as BulletWorldUnman; - return BSAPICPP.RayTest2(worldu.ptr, from, to, filterGroup, filterMask); -} - -// ===================================================================================== -// Debugging -public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletBodyUnman bodyu = collisionObject as BulletBodyUnman; - BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr); -} - -public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletShapeUnman shapeu = collisionShape as BulletShapeUnman; - BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr); -} - -public override void DumpConstraint(BulletWorld world, BulletConstraint constrain) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BulletConstraintUnman constrainu = constrain as BulletConstraintUnman; - BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr); -} - -public override void DumpActivationInfo(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.DumpActivationInfo2(worldu.ptr); -} - -public override void DumpAllInfo(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.DumpAllInfo2(worldu.ptr); -} - -public override void DumpPhysicsStatistics(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.DumpPhysicsStatistics2(worldu.ptr); -} -public override void ResetBroadphasePool(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.ResetBroadphasePool(worldu.ptr); -} -public override void ResetConstraintSolver(BulletWorld world) -{ - BulletWorldUnman worldu = world as BulletWorldUnman; - BSAPICPP.ResetConstraintSolver(worldu.ptr); -} - -// ===================================================================================== -// ===================================================================================== -// ===================================================================================== -// ===================================================================================== -// ===================================================================================== -// The actual interface to the unmanaged code -static class BSAPICPP -{ -// =============================================================================== -// Link back to the managed code for outputting log messages -[UnmanagedFunctionPointer(CallingConvention.Cdecl)] -public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); - -// =============================================================================== -// Initialization and simulation -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms, - int maxCollisions, IntPtr collisionArray, - int maxUpdates, IntPtr updateArray, - DebugLogCallback logRoutine); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep, - out int updatedEntityCount, out int collidersCount); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void Shutdown2(IntPtr sim); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool PushUpdate2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value); - -// ===================================================================================== -// Mesh, hull, shape and body creation helper routines -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateMeshShape2(IntPtr world, - int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, - int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateGImpactShape2(IntPtr world, - int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, - int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateHullShape2(IntPtr world, - int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape, HACDParams parms); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr BuildConvexHullShapeFromMesh2(IntPtr world, IntPtr meshShape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateConvexHullShape2(IntPtr world, - int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices, - int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices ); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsNativeShape2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetShapeCollisionMargin(IntPtr shape, float margin); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern int GetNumberOfCompoundChildren2(IntPtr cShape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void UpdateChildTransform2(IntPtr pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern int GetBodyType2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DestroyObject2(IntPtr sim, IntPtr obj); - -// ===================================================================================== -// Terrain creation and helper routines -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight, - [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, - float scaleFactor, float collisionMargin); - -// ===================================================================================== -// Constraint creation and helper routines -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, - Vector3 frame1loc, Quaternion frame1rot, - Vector3 frame2loc, Quaternion frame2rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2, - Vector3 joinPoint, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr Create6DofConstraintFixed2(IntPtr world, IntPtr obj1, - Vector3 frameInBloc, Quaternion frameInBrot, - bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr Create6DofSpringConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, - Vector3 frame1loc, Quaternion frame1rot, - Vector3 frame2loc, Quaternion frame2rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, - Vector3 pivotinA, Vector3 pivotinB, - Vector3 axisInA, Vector3 axisInB, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateSliderConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, - Vector3 frameInAloc, Quaternion frameInArot, - Vector3 frameInBloc, Quaternion frameInBrot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateConeTwistConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, - Vector3 frameInAloc, Quaternion frameInArot, - Vector3 frameInBloc, Quaternion frameInBrot, - bool disableCollisionsBetweenLinkedBodies); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreateGearConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, - Vector3 axisInA, Vector3 axisInB, - float ratio, bool disableCollisionsBetweenLinkedBodies); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr CreatePoint2PointConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2, - Vector3 pivotInA, Vector3 pivotInB, - bool disableCollisionsBetweenLinkedBodies); - - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SetFrames2(IntPtr constrain, - Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool UseFrameOffset2(IntPtr constrain, float enable); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool HingeSetLimits2(IntPtr constrain, float low, float high, float softness, float bias, float relaxation); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool ConstraintSpringEnable2(IntPtr constrain, int index, float numericTrueFalse); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool ConstraintSpringSetEquilibriumPoint2(IntPtr constrain, int index, float equilibriumPoint); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool ConstraintSpringSetStiffness2(IntPtr constrain, int index, float stiffness); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool ConstraintSpringSetDamping2(IntPtr constrain, int index, float damping); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SliderSetLimits2(IntPtr constrain, int lowerUpper, int linAng, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SliderSet2(IntPtr constrain, int softRestDamp, int dirLimOrtho, int linAng, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SliderMotorEnable2(IntPtr constrain, int linAng, float numericTrueFalse); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SliderMotor2(IntPtr constrain, int forceVel, int linAng, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool CalculateTransforms2(IntPtr constrain); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain); - -// ===================================================================================== -// btCollisionWorld entries -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void UpdateAabbs2(IntPtr world); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool GetForceUpdateAllAabbs2(IntPtr world); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force); - -// ===================================================================================== -// btDynamicsWorld entries -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool ClearCollisionProxyCache2(IntPtr world, IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain); -// ===================================================================================== -// btCollisionObject entries -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool HasAnisotripicFriction2(IntPtr constrain); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetContactProcessingThreshold2(IntPtr obj, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetContactProcessingThreshold2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsStaticObject2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsKinematicObject2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsStaticOrKinematicObject2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool HasContactResponse2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr GetCollisionShape2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern int GetActivationState2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetActivationState2(IntPtr obj, int state); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetDeactivationTime2(IntPtr obj, float dtime); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetDeactivationTime2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ForceActivationState2(IntPtr obj, ActivationState state); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void Activate2(IntPtr obj, bool forceActivation); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsActive2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetRestitution2(IntPtr obj, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetRestitution2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetFriction2(IntPtr obj, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetFriction2(IntPtr obj); - - /* Haven't defined the type 'Transform' -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Transform GetWorldTransform2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void setWorldTransform2(IntPtr obj, Transform trans); - */ - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetPosition2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Quaternion GetOrientation2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr GetBroadphaseHandle2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle); - - /* -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Transform GetInterpolationWorldTransform2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans); - */ - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetHitFraction2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetHitFraction2(IntPtr obj, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern CollisionFlags GetCollisionFlags2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetCcdMotionThreshold2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetCcdMotionThreshold2(IntPtr obj, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetCcdSweptSphereRadius2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr GetUserPointer2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetUserPointer2(IntPtr obj, IntPtr val); - -// ===================================================================================== -// btRigidBody entries -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyGravity2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetGravity2(IntPtr obj, Vector3 val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetGravity2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetLinearDamping2(IntPtr obj, float lin_damping); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetAngularDamping2(IntPtr obj, float ang_damping); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetLinearDamping2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetAngularDamping2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetLinearSleepingThreshold2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetAngularSleepingThreshold2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyDamping2(IntPtr obj, float timeStep); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetLinearFactor2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor); - - /* -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans); - */ - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot); - -// Add a force to the object as if its mass is one. -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force); - -// Set the force being applied to the object as if its mass is one. -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetObjectForce2(IntPtr obj, Vector3 force); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetTotalForce2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetTotalTorque2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyTorque2(IntPtr obj, Vector3 torque); - -// Apply force at the given point. Will add torque to the object. -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos); - -// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp); - -// Apply impulse to the object's torque. Force is scaled by object's mass. -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp); - -// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ClearForces2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ClearAllForces2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void UpdateInertiaTensor2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj); - - /* -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Transform GetCenterOfMassTransform2(IntPtr obj); - */ - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetLinearVelocity2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetAngularVelocity2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void Translate2(IntPtr obj, Vector3 trans); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void UpdateDeactivation2(IntPtr obj, float timeStep); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool WantsSleeping2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetAngularFactor2(IntPtr obj, float factor); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetAngularFactor2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsInWorld2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern int GetNumConstraintRefs2(IntPtr obj); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask); - -// ===================================================================================== -// btCollisionShape entries - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetAngularMotionDisc2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsPolyhedral2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsConvex2d2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsConvex2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsNonMoving2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsConcave2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsCompound2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsSoftBody2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern bool IsInfinite2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 GetLocalScaling2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern int GetShapeType2(IntPtr shape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void SetMargin2(IntPtr shape, float val); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern float GetMargin2(IntPtr shape); - - -// ===================================================================================== -// Raycast -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern SweepHit ConvexSweepTest2(IntPtr sim, IntPtr obj, Vector3 from, Vector3 to, float margin); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern RaycastHit RayTest2(IntPtr sim, Vector3 from, Vector3 to, uint filterGroup, uint filterMask); - -// ===================================================================================== -// Debugging -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpActivationInfo2(IntPtr sim); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpAllInfo2(IntPtr sim); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void DumpPhysicsStatistics2(IntPtr sim); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ResetBroadphasePool(IntPtr sim); - -[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern void ResetConstraintSolver(IntPtr sim); - -} - -} - -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs index a439cc0dcc..4e4ac2f433 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSAPIXNA.cs @@ -42,2435 +42,2439 @@ using BulletXNA.BulletCollision.CollisionDispatch; namespace OpenSim.Region.PhysicsModule.BulletS { -public sealed class BSAPIXNA : BSAPITemplate -{ -private sealed class BulletWorldXNA : BulletWorld -{ - public DiscreteDynamicsWorld world; - public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx) - : base(id, physScene) + public sealed class BSAPIXNA : BSAPITemplate { - world = xx; - } -} - -private sealed class BulletBodyXNA : BulletBody -{ - public CollisionObject body; - public RigidBody rigidBody { get { return RigidBody.Upcast(body); } } - - public BulletBodyXNA(uint id, CollisionObject xx) - : base(id) - { - body = xx; - } - public override bool HasPhysicalBody - { - get { return body != null; } - } - public override void Clear() - { - body = null; - } - public override string AddrString - { - get { return "XNARigidBody"; } - } -} - -private sealed class BulletShapeXNA : BulletShape -{ - public CollisionShape shape; - public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) - : base() - { - shape = xx; - shapeType = typ; - } - public override bool HasPhysicalShape - { - get { return shape != null; } - } - public override void Clear() - { - shape = null; - } - public override BulletShape Clone() - { - return new BulletShapeXNA(shape, shapeType); - } - public override bool ReferenceSame(BulletShape other) - { - BulletShapeXNA otheru = other as BulletShapeXNA; - return (otheru != null) && (this.shape == otheru.shape); - - } - public override string AddrString - { - get { return "XNACollisionShape"; } - } -} -private sealed class BulletConstraintXNA : BulletConstraint -{ - public TypedConstraint constrain; - public BulletConstraintXNA(TypedConstraint xx) : base() - { - constrain = xx; - } - - public override void Clear() - { - constrain = null; - } - public override bool HasPhysicalConstraint { get { return constrain != null; } } - - // Used for log messages for a unique display of the memory/object allocated to this instance - public override string AddrString - { - get { return "XNAConstraint"; } - } -} - internal int m_maxCollisions; - internal CollisionDesc[] UpdatedCollisions; - internal int LastCollisionDesc = 0; - internal int m_maxUpdatesPerFrame; - internal int LastEntityProperty = 0; - - internal EntityProperties[] UpdatedObjects; - internal Dictionary specialCollisionObjects; - - private static int m_collisionsThisFrame; - private BSScene PhysicsScene { get; set; } - - public override string BulletEngineName { get { return "BulletXNA"; } } - public override string BulletEngineVersion { get; protected set; } - - public BSAPIXNA(string paramName, BSScene physScene) - { - PhysicsScene = physScene; - } - - /// - /// - /// - /// - /// - public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - CollisionObject collisionObject = ((BulletBodyXNA)pBody).body; - if (body != null) - world.RemoveRigidBody(body); - else if (collisionObject != null) - world.RemoveCollisionObject(collisionObject); - else - return false; - return true; - } - - public override bool ClearCollisionProxyCache(BulletWorld pWorld, BulletBody pBody) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - RigidBody body = ((BulletBodyXNA)pBody).rigidBody; - CollisionObject collisionObject = ((BulletBodyXNA)pBody).body; - if (body != null && collisionObject != null && collisionObject.GetBroadphaseHandle() != null) + private sealed class BulletWorldXNA : BulletWorld { - world.RemoveCollisionObject(collisionObject); - world.AddCollisionObject(collisionObject); - } - return true; - } - - public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; - world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); - - return true; - - } - - public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; - world.RemoveConstraint(constraint); - return true; - } - - public override void SetRestitution(BulletBody pCollisionObject, float pRestitution) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - collisionObject.SetRestitution(pRestitution); - } - - public override int GetShapeType(BulletShape pShape) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - return (int)shape.GetShapeType(); - } - public override void SetMargin(BulletShape pShape, float pMargin) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - shape.SetMargin(pMargin); - } - - public override float GetMargin(BulletShape pShape) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - return shape.GetMargin(); - } - - public override void SetLocalScaling(BulletShape pShape, Vector3 pScale) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); - shape.SetLocalScaling(ref vec); - - } - - public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - collisionObject.SetContactProcessingThreshold(contactprocessingthreshold); - } - - public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - collisionObject.SetCcdMotionThreshold(pccdMotionThreashold); - } - - public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius); - } - - public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z)); - } - - public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags(); - existingcollisionFlags |= pcollisionFlags; - collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); - return (CollisionFlags) (uint) existingcollisionFlags; - } - - public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - CollisionObject cbody = (pBody as BulletBodyXNA).body; - RigidBody rbody = cbody as RigidBody; - - // Bullet resets several variables when an object is added to the world. In particular, - // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic - // type. Of course, the collision flags in the broadphase proxy are initialized to default. - IndexedMatrix origPos = cbody.GetWorldTransform(); - if (rbody != null) - { - IndexedVector3 origGrav = rbody.GetGravity(); - world.AddRigidBody(rbody); - rbody.SetGravity(origGrav); - } - else - { - world.AddCollisionObject(cbody); - } - cbody.SetWorldTransform(origPos); - - pBody.ApplyCollisionMask(pWorld.physicsScene); - - //if (body.GetBroadphaseHandle() != null) - // world.UpdateSingleAabb(body); - return true; - } - - public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState); - } - - public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - world.UpdateSingleAabb(collisionObject); - } - - public override void UpdateAabbs(BulletWorld pWorld) { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - world.UpdateAabbs(); - } - public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - return world.GetForceUpdateAllAabbs(); - - } - public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - world.SetForceUpdateAllAabbs(pForce); - } - - public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; - collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; - if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0) - return false; - return true; - } - - public override void ClearAllForces(BulletBody pCollisionObject) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0); - collisionObject.SetInterpolationLinearVelocity(ref zeroVector); - collisionObject.SetInterpolationAngularVelocity(ref zeroVector); - IndexedMatrix bodytransform = collisionObject.GetWorldTransform(); - - collisionObject.SetInterpolationWorldTransform(ref bodytransform); - - if (collisionObject is RigidBody) - { - RigidBody rigidbody = collisionObject as RigidBody; - rigidbody.SetLinearVelocity(zeroVector); - rigidbody.SetAngularVelocity(zeroVector); - rigidbody.ClearForces(); - } - } - - public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); - collisionObject.SetInterpolationAngularVelocity(ref vec); - } - - public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); - body.SetAngularVelocity(ref vec); - } - public override Vector3 GetTotalForce(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 iv3 = body.GetTotalForce(); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - public override Vector3 GetTotalTorque(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 iv3 = body.GetTotalTorque(); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 iv3 = body.GetInvInertiaDiagLocal(); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z); - body.SetInvInertiaDiagLocal(ref iv3); - } - public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z); - IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); - body.ApplyForce(ref forceiv3, ref posiv3); - } - public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z); - IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); - body.ApplyImpulse(ref impiv3, ref posiv3); - } - - public override void ClearForces(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - body.ClearForces(); - } - - public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); - IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, - _orientation.W); - IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); - mat._origin = vposition; - collisionObject.SetWorldTransform(mat); - - } - - public override Vector3 GetPosition(BulletBody pCollisionObject) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin; - return new Vector3(pos.X, pos.Y, pos.Z); - } - - public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - IndexedVector3 inertia = IndexedVector3.Zero; - shape.CalculateLocalInertia(pphysMass, out inertia); - return new Vector3(inertia.X, inertia.Y, inertia.Z); - } - - public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - if (body != null) // Can't set mass props on collision object. - { - IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z); - body.SetMassProps(pphysMass, inertia); - } - } - - - public override void SetObjectForce(BulletBody pBody, Vector3 _force) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z); - body.SetTotalForce(ref force); - } - - public override void SetFriction(BulletBody pCollisionObject, float _currentFriction) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - collisionObject.SetFriction(_currentFriction); - } - - public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z); - body.SetLinearVelocity(velocity); - } - - public override void Activate(BulletBody pCollisionObject, bool pforceactivation) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - collisionObject.Activate(pforceactivation); - - } - - public override Quaternion GetOrientation(BulletBody pCollisionObject) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation(); - return new Quaternion(mat.X, mat.Y, mat.Z, mat.W); - } - - public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags(); - existingcollisionFlags &= ~pcollisionFlags; - collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); - return (CollisionFlags)(uint)existingcollisionFlags; - } - - public override float GetCcdMotionThreshold(BulletBody pCollisionObject) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - return collisionObject.GetCcdSquareMotionThreshold(); - } - - public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - return collisionObject.GetCcdSweptSphereRadius(); - - } - - public override IntPtr GetUserPointer(BulletBody pCollisionObject) - { - CollisionObject shape = (pCollisionObject as BulletBodyXNA).body; - return (IntPtr)shape.GetUserPointer(); - } - - public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val) - { - CollisionObject shape = (pCollisionObject as BulletBodyXNA).body; - shape.SetUserPointer(val); - } - - public override void SetGravity(BulletBody pBody, Vector3 pGravity) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - if (body != null) // Can't set collisionobject.set gravity - { - IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z); - body.SetGravity(gravity); - } - } - - public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; - world.RemoveConstraint(constraint); - return true; - } - - public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) - { - Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; - IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); - IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); - constraint.SetLinearLowerLimit(lowlimit); - constraint.SetLinearUpperLimit(highlimit); - return true; - } - - public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) - { - Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; - IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); - IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); - constraint.SetAngularLowerLimit(lowlimit); - constraint.SetAngularUpperLimit(highlimit); - return true; - } - - public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt) - { - Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; - constraint.SetOverrideNumSolverIterations((int)cnt); - } - - public override bool CalculateTransforms(BulletConstraint pConstraint) - { - Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; - constraint.CalculateTransforms(); - return true; - } - - public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2) - { - Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; - constraint.SetEnabled((p_2 == 0) ? false : true); - } - - - public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, - Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, - bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) - - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; - RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; - IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); - IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); - IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); - frame1._origin = frame1v; - - IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); - IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); - IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); - frame2._origin = frame2v; - - Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, - puseLinearReferenceFrameA); - consttr.CalculateTransforms(); - world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); - - return new BulletConstraintXNA(consttr); - } - - public override BulletConstraint Create6DofConstraintFixed(BulletWorld pWorld, BulletBody pBody1, - Vector3 pframe1, Quaternion pframe1rot, - bool pUseLinearReferenceFrameB, bool pdisableCollisionsBetweenLinkedBodies) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; - IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); - IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); - IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); - frame1._origin = frame1v; - - Generic6DofConstraint consttr = new Generic6DofConstraint(body1, ref frame1, pUseLinearReferenceFrameB); - consttr.CalculateTransforms(); - world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); - - return new BulletConstraintXNA(consttr); - } - - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; - RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; - IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); - IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); - - IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); - IndexedMatrix mat = IndexedMatrix.Identity; - mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); - frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint; - frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint; - - Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); - consttr.CalculateTransforms(); - world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies); - - return new BulletConstraintXNA(consttr); - } - //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); - public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot) - { - Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; - IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); - IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); - IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); - frame1._origin = frame1v; - - IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); - IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); - IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); - frame2._origin = frame2v; - constraint.SetFrames(ref frame1, ref frame2); - return true; - } - - public override Vector3 GetLinearVelocity(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 iv3 = body.GetLinearVelocity(); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - public override Vector3 GetAngularVelocity(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 iv3 = body.GetAngularVelocity(); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); - IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - public override void Translate(BulletBody pCollisionObject, Vector3 trans) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z)); - } - public override void UpdateDeactivation(BulletBody pBody, float timeStep) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - body.UpdateDeactivation(timeStep); - } - - public override bool WantsSleeping(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - return body.WantsSleeping(); - } - - public override void SetAngularFactor(BulletBody pBody, float factor) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - body.SetAngularFactor(factor); - } - - public override Vector3 GetAngularFactor(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 iv3 = body.GetAngularFactor(); - return new Vector3(iv3.X, iv3.Y, iv3.Z); - } - - public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - return world.IsInWorld(collisionObject); - } - - public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain; - body.AddConstraintRef(constrain); - } - - public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain; - body.RemoveConstraintRef(constrain); - } - - public override BulletConstraint GetConstraintRef(BulletBody pBody, int index) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - return new BulletConstraintXNA(body.GetConstraintRef(index)); - } - - public override int GetNumConstraintRefs(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - return body.GetNumConstraintRefs(); - } - - public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z); - collisionObject.SetInterpolationLinearVelocity(ref velocity); - } - - public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff) - { - Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; - constraint.SetUseFrameOffset((onOff == 0) ? false : true); - return true; - } - //SetBreakingImpulseThreshold(m_constraint.ptr, threshold); - public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold) - { - Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; - constraint.SetBreakingImpulseThreshold(threshold); - return true; - } - public override bool HingeSetLimits(BulletConstraint pConstraint, float low, float high, float softness, float bias, float relaxation) - { - HingeConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as HingeConstraint; - if (softness == HINGE_NOT_SPECIFIED) - constraint.SetLimit(low, high); - else - constraint.SetLimit(low, high, softness, bias, relaxation); - return true; - } - public override bool SpringEnable(BulletConstraint pConstraint, int index, float numericTrueFalse) - { - Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; - constraint.EnableSpring(index, (numericTrueFalse == 0f ? false : true)); - return true; - } - - public override bool SpringSetEquilibriumPoint(BulletConstraint pConstraint, int index, float equilibriumPoint) - { - Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; - if (index == SPRING_NOT_SPECIFIED) - { - constraint.SetEquilibriumPoint(); - } - else - { - if (equilibriumPoint == SPRING_NOT_SPECIFIED) - constraint.SetEquilibriumPoint(index); - else - constraint.SetEquilibriumPoint(index, equilibriumPoint); - } - return true; - } - - public override bool SpringSetStiffness(BulletConstraint pConstraint, int index, float stiffness) - { - Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; - constraint.SetStiffness(index, stiffness); - return true; - } - - public override bool SpringSetDamping(BulletConstraint pConstraint, int index, float damping) - { - Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; - constraint.SetDamping(index, damping); - return true; - } - - public override bool SliderSetLimits(BulletConstraint pConstraint, int lowerUpper, int linAng, float val) - { - SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; - switch (lowerUpper) - { - case SLIDER_LOWER_LIMIT: - switch (linAng) - { - case SLIDER_LINEAR: - constraint.SetLowerLinLimit(val); - break; - case SLIDER_ANGULAR: - constraint.SetLowerAngLimit(val); - break; - } - break; - case SLIDER_UPPER_LIMIT: - switch (linAng) - { - case SLIDER_LINEAR: - constraint.SetUpperLinLimit(val); - break; - case SLIDER_ANGULAR: - constraint.SetUpperAngLimit(val); - break; - } - break; - } - return true; - } - public override bool SliderSet(BulletConstraint pConstraint, int softRestDamp, int dirLimOrtho, int linAng, float val) - { - SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; - switch (softRestDamp) - { - case SLIDER_SET_SOFTNESS: - switch (dirLimOrtho) - { - case SLIDER_SET_DIRECTION: - switch (linAng) - { - case SLIDER_LINEAR: constraint.SetSoftnessDirLin(val); break; - case SLIDER_ANGULAR: constraint.SetSoftnessDirAng(val); break; - } - break; - case SLIDER_SET_LIMIT: - switch (linAng) - { - case SLIDER_LINEAR: constraint.SetSoftnessLimLin(val); break; - case SLIDER_ANGULAR: constraint.SetSoftnessLimAng(val); break; - } - break; - case SLIDER_SET_ORTHO: - switch (linAng) - { - case SLIDER_LINEAR: constraint.SetSoftnessOrthoLin(val); break; - case SLIDER_ANGULAR: constraint.SetSoftnessOrthoAng(val); break; - } - break; - } - break; - case SLIDER_SET_RESTITUTION: - switch (dirLimOrtho) - { - case SLIDER_SET_DIRECTION: - switch (linAng) - { - case SLIDER_LINEAR: constraint.SetRestitutionDirLin(val); break; - case SLIDER_ANGULAR: constraint.SetRestitutionDirAng(val); break; - } - break; - case SLIDER_SET_LIMIT: - switch (linAng) - { - case SLIDER_LINEAR: constraint.SetRestitutionLimLin(val); break; - case SLIDER_ANGULAR: constraint.SetRestitutionLimAng(val); break; - } - break; - case SLIDER_SET_ORTHO: - switch (linAng) - { - case SLIDER_LINEAR: constraint.SetRestitutionOrthoLin(val); break; - case SLIDER_ANGULAR: constraint.SetRestitutionOrthoAng(val); break; - } - break; - } - break; - case SLIDER_SET_DAMPING: - switch (dirLimOrtho) - { - case SLIDER_SET_DIRECTION: - switch (linAng) - { - case SLIDER_LINEAR: constraint.SetDampingDirLin(val); break; - case SLIDER_ANGULAR: constraint.SetDampingDirAng(val); break; - } - break; - case SLIDER_SET_LIMIT: - switch (linAng) - { - case SLIDER_LINEAR: constraint.SetDampingLimLin(val); break; - case SLIDER_ANGULAR: constraint.SetDampingLimAng(val); break; - } - break; - case SLIDER_SET_ORTHO: - switch (linAng) - { - case SLIDER_LINEAR: constraint.SetDampingOrthoLin(val); break; - case SLIDER_ANGULAR: constraint.SetDampingOrthoAng(val); break; - } - break; - } - break; - } - return true; - } - public override bool SliderMotorEnable(BulletConstraint pConstraint, int linAng, float numericTrueFalse) - { - SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; - switch (linAng) - { - case SLIDER_LINEAR: - constraint.SetPoweredLinMotor(numericTrueFalse == 0.0 ? false : true); - break; - case SLIDER_ANGULAR: - constraint.SetPoweredAngMotor(numericTrueFalse == 0.0 ? false : true); - break; - } - return true; - } - public override bool SliderMotor(BulletConstraint pConstraint, int forceVel, int linAng, float val) - { - SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; - switch (forceVel) - { - case SLIDER_MOTOR_VELOCITY: - switch (linAng) - { - case SLIDER_LINEAR: - constraint.SetTargetLinMotorVelocity(val); - break; - case SLIDER_ANGULAR: - constraint.SetTargetAngMotorVelocity(val); - break; - } - break; - case SLIDER_MAX_MOTOR_FORCE: - switch (linAng) - { - case SLIDER_LINEAR: - constraint.SetMaxLinMotorForce(val); - break; - case SLIDER_ANGULAR: - constraint.SetMaxAngMotorForce(val); - break; - } - break; - } - return true; - } - - //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping); - public override void SetAngularDamping(BulletBody pBody, float angularDamping) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - float lineardamping = body.GetLinearDamping(); - body.SetDamping(lineardamping, angularDamping); - - } - - public override void UpdateInertiaTensor(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - if (body != null) // can't update inertia tensor on CollisionObject - body.UpdateInertiaTensor(); - } - - public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape) - { - CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape; - shape.RecalculateLocalAabb(); - } - - //BulletSimAPI.GetCollisionFlags(PhysBody.ptr) - public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - uint flags = (uint)collisionObject.GetCollisionFlags(); - return (CollisionFlags) flags; - } - - public override void SetDamping(BulletBody pBody, float pLinear, float pAngular) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - body.SetDamping(pLinear, pAngular); - } - //PhysBody.ptr, PhysicsScene.Params.deactivationTime); - public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - collisionObject.SetDeactivationTime(pDeactivationTime); - } - //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); - public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold); - } - - public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - return (CollisionObjectTypes)(int) collisionObject.GetInternalType(); - } - - public override void ApplyGravity(BulletBody pBody) - { - - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - body.ApplyGravity(); - } - - public override Vector3 GetGravity(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 gravity = body.GetGravity(); - return new Vector3(gravity.X, gravity.Y, gravity.Z); - } - - public override void SetLinearDamping(BulletBody pBody, float lin_damping) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - float angularDamping = body.GetAngularDamping(); - body.SetDamping(lin_damping, angularDamping); - } - - public override float GetLinearDamping(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - return body.GetLinearDamping(); - } - - public override float GetAngularDamping(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - return body.GetAngularDamping(); - } - - public override float GetLinearSleepingThreshold(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - return body.GetLinearSleepingThreshold(); - } - - public override void ApplyDamping(BulletBody pBody, float timeStep) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - body.ApplyDamping(timeStep); - } - - public override Vector3 GetLinearFactor(BulletBody pBody) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 linearFactor = body.GetLinearFactor(); - return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z); - } - - public override void SetLinearFactor(BulletBody pBody, Vector3 factor) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z)); - } - - public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W); - IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat); - mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z); - body.SetCenterOfMassTransform( ref mat); - /* TODO: double check this */ - } - - //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum); - public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); - body.ApplyCentralForce(ref fSum); - } - public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); - body.ApplyCentralImpulse(ref fSum); - } - public override void ApplyTorque(BulletBody pBody, Vector3 pfSum) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); - body.ApplyTorque(ref fSum); - } - public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum) - { - RigidBody body = (pBody as BulletBodyXNA).rigidBody; - IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); - body.ApplyTorqueImpulse(ref fSum); - } - - public override void DestroyObject(BulletWorld pWorld, BulletBody pBody) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - CollisionObject co = (pBody as BulletBodyXNA).rigidBody; - RigidBody bo = co as RigidBody; - if (bo == null) - { - - if (world.IsInWorld(co)) + public DiscreteDynamicsWorld world; + public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx) + : base(id, physScene) { - world.RemoveCollisionObject(co); - } - } - else - { - - if (world.IsInWorld(bo)) - { - world.RemoveRigidBody(bo); - } - } - if (co != null) - { - if (co.GetUserPointer() != null) - { - uint localId = (uint) co.GetUserPointer(); - if (specialCollisionObjects.ContainsKey(localId)) - { - specialCollisionObjects.Remove(localId); - } + world = xx; } } - } - - public override void Shutdown(BulletWorld pWorld) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - world.Cleanup(); - } - - public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id) - { - CollisionShape shape1 = (pShape as BulletShapeXNA).shape; - - // TODO: Turn this from a reference copy to a Value Copy. - BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); - - return shape2; - } - - public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape) - { - //TODO: - return false; - } - //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); - - public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) - { - CollisionWorld world = (pWorld as BulletWorldXNA).world; - IndexedMatrix mat = - IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, - pRawOrientation.Z, pRawOrientation.W)); - mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); - CollisionShape shape = (pShape as BulletShapeXNA).shape; - //UpdateSingleAabb(world, shape); - // TODO: Feed Update array into null - SimMotionState motionState = new SimMotionState(this, pLocalID, mat, null); - RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero); - RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, motionState, shape, IndexedVector3.Zero) - { - m_mass = 0 - }; - /* - m_mass = mass; - m_motionState =motionState; - m_collisionShape = collisionShape; - m_localInertia = localInertia; - m_linearDamping = 0f; - m_angularDamping = 0f; - m_friction = 0.5f; - m_restitution = 0f; - m_linearSleepingThreshold = 0.8f; - m_angularSleepingThreshold = 1f; - m_additionalDamping = false; - m_additionalDampingFactor = 0.005f; - m_additionalLinearDampingThresholdSqr = 0.01f; - m_additionalAngularDampingThresholdSqr = 0.01f; - m_additionalAngularDampingFactor = 0.01f; - m_startWorldTransform = IndexedMatrix.Identity; - */ - body.SetUserPointer(pLocalID); - - return new BulletBodyXNA(pLocalID, body); - } - - - public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) - { - - IndexedMatrix mat = - IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, - pRawOrientation.Z, pRawOrientation.W)); - mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); - - CollisionShape shape = (pShape as BulletShapeXNA).shape; - - // TODO: Feed Update array into null - RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero); - body.SetWorldTransform(mat); - body.SetUserPointer(pLocalID); - return new BulletBodyXNA(pLocalID, body); - } - //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); - public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags); - return (CollisionFlags)collisionObject.GetCollisionFlags(); - } - - public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) - { - - /* TODO */ - return Vector3.Zero; - } - public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } - public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; } - public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; } - public override bool IsStaticObject(BulletBody pCollisionObject) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - return collisionObject.IsStaticObject(); - - } - public override bool IsKinematicObject(BulletBody pCollisionObject) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - return collisionObject.IsKinematicObject(); - } - public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - return collisionObject.IsStaticOrKinematicObject(); - } - public override bool HasContactResponse(BulletBody pCollisionObject) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - return collisionObject.HasContactResponse(); - } - public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; } - public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ } - public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; } - public override bool IsActive(BulletBody pBody) { /* TODO */ return false; } - public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; } - public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; } - public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ } - public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; } - - //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); - public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - collisionObject.SetHitFraction(pHitFraction); - } - //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale); - public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); - CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight); - capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin); - capsuleShapeZ.SetLocalScaling(ref scale); - - return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ; - } - - public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, - int maxCollisions, ref CollisionDesc[] collisionArray, - int maxUpdates, ref EntityProperties[] updateArray - ) - { - - UpdatedObjects = updateArray; - UpdatedCollisions = collisionArray; - /* TODO */ - ConfigurationParameters[] configparms = new ConfigurationParameters[1]; - configparms[0] = parms; - Vector3 worldExtent = maxPosition; - m_maxCollisions = maxCollisions; - m_maxUpdatesPerFrame = maxUpdates; - specialCollisionObjects = new Dictionary(); - - return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); - } - - private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, - ConfigurationParameters[] o, - int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, - int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, - object mDebugLogCallbackHandle) - { - CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); - - p.angularDamping = BSParam.AngularDamping; - p.defaultFriction = o[0].defaultFriction; - p.defaultFriction = o[0].defaultFriction; - p.defaultDensity = o[0].defaultDensity; - p.defaultRestitution = o[0].defaultRestitution; - p.collisionMargin = o[0].collisionMargin; - p.gravity = o[0].gravity; - - p.linearDamping = BSParam.LinearDamping; - p.angularDamping = BSParam.AngularDamping; - p.deactivationTime = BSParam.DeactivationTime; - p.linearSleepingThreshold = BSParam.LinearSleepingThreshold; - p.angularSleepingThreshold = BSParam.AngularSleepingThreshold; - p.ccdMotionThreshold = BSParam.CcdMotionThreshold; - p.ccdSweptSphereRadius = BSParam.CcdSweptSphereRadius; - p.contactProcessingThreshold = BSParam.ContactProcessingThreshold; - - p.terrainImplementation = BSParam.TerrainImplementation; - p.terrainFriction = BSParam.TerrainFriction; - - p.terrainHitFraction = BSParam.TerrainHitFraction; - p.terrainRestitution = BSParam.TerrainRestitution; - p.terrainCollisionMargin = BSParam.TerrainCollisionMargin; - - p.avatarFriction = BSParam.AvatarFriction; - p.avatarStandingFriction = BSParam.AvatarStandingFriction; - p.avatarDensity = BSParam.AvatarDensity; - p.avatarRestitution = BSParam.AvatarRestitution; - p.avatarCapsuleWidth = BSParam.AvatarCapsuleWidth; - p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; - p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; - p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; - - p.vehicleAngularDamping = BSParam.VehicleAngularDamping; - - p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; - p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; - p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; - p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs; - p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder; - p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands; - p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching; - p.numberOfSolverIterations = o[0].numberOfSolverIterations; - - p.linksetImplementation = BSParam.LinksetImplementation; - p.linkConstraintUseFrameOffset = BSParam.NumericBool(BSParam.LinkConstraintUseFrameOffset); - p.linkConstraintEnableTransMotor = BSParam.NumericBool(BSParam.LinkConstraintEnableTransMotor); - p.linkConstraintTransMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; - p.linkConstraintTransMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; - p.linkConstraintERP = BSParam.LinkConstraintERP; - p.linkConstraintCFM = BSParam.LinkConstraintCFM; - p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; - p.physicsLoggingFrames = o[0].physicsLoggingFrames; - DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); - - DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); - CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); - - - if (p.maxPersistantManifoldPoolSize > 0) - cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize; - if (p.shouldDisableContactPoolDynamicAllocation !=0) - m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION); - //if (p.maxCollisionAlgorithmPoolSize >0 ) - - DbvtBroadphase m_broadphase = new DbvtBroadphase(); - //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0); - //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256); - - //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true); - m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback()); - - SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver(); - - DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci); - - world.LastCollisionDesc = 0; - world.LastEntityProperty = 0; - - world.WorldSettings.Params = p; - world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0); - world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD; - if (p.shouldRandomizeSolverOrder != 0) - world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER; - - world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0); - //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port - - if (p.shouldEnableFrictionCaching != 0) - world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING; - - if (p.numberOfSolverIterations > 0) - world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations; - - - world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping; - world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution; - world.GetSolverInfo().m_globalCfm = 0.0f; - world.GetSolverInfo().m_tau = 0.6f; - world.GetSolverInfo().m_friction = 0.3f; - world.GetSolverInfo().m_maxErrorReduction = 20f; - world.GetSolverInfo().m_numIterations = 10; - world.GetSolverInfo().m_erp = 0.2f; - world.GetSolverInfo().m_erp2 = 0.1f; - world.GetSolverInfo().m_sor = 1.0f; - world.GetSolverInfo().m_splitImpulse = false; - world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f; - world.GetSolverInfo().m_linearSlop = 0.0f; - world.GetSolverInfo().m_warmstartingFactor = 0.85f; - world.GetSolverInfo().m_restingContactRestitutionThreshold = 2; - world.SetForceUpdateAllAabbs(true); - - //BSParam.TerrainImplementation = 0; - world.SetGravity(new IndexedVector3(0,0,p.gravity)); - - // Turn off Pooling since globals and pooling are bad for threading. - BulletGlobals.VoronoiSimplexSolverPool.SetPoolingEnabled(false); - BulletGlobals.SubSimplexConvexCastPool.SetPoolingEnabled(false); - BulletGlobals.ManifoldPointPool.SetPoolingEnabled(false); - BulletGlobals.CastResultPool.SetPoolingEnabled(false); - BulletGlobals.SphereShapePool.SetPoolingEnabled(false); - BulletGlobals.DbvtNodePool.SetPoolingEnabled(false); - BulletGlobals.SingleRayCallbackPool.SetPoolingEnabled(false); - BulletGlobals.SubSimplexClosestResultPool.SetPoolingEnabled(false); - BulletGlobals.GjkPairDetectorPool.SetPoolingEnabled(false); - BulletGlobals.DbvtTreeColliderPool.SetPoolingEnabled(false); - BulletGlobals.SingleSweepCallbackPool.SetPoolingEnabled(false); - BulletGlobals.BroadphaseRayTesterPool.SetPoolingEnabled(false); - BulletGlobals.ClosestNotMeConvexResultCallbackPool.SetPoolingEnabled(false); - BulletGlobals.GjkEpaPenetrationDepthSolverPool.SetPoolingEnabled(false); - BulletGlobals.ContinuousConvexCollisionPool.SetPoolingEnabled(false); - BulletGlobals.DbvtStackDataBlockPool.SetPoolingEnabled(false); - - BulletGlobals.BoxBoxCollisionAlgorithmPool.SetPoolingEnabled(false); - BulletGlobals.CompoundCollisionAlgorithmPool.SetPoolingEnabled(false); - BulletGlobals.ConvexConcaveCollisionAlgorithmPool.SetPoolingEnabled(false); - BulletGlobals.ConvexConvexAlgorithmPool.SetPoolingEnabled(false); - BulletGlobals.ConvexPlaneAlgorithmPool.SetPoolingEnabled(false); - BulletGlobals.SphereBoxCollisionAlgorithmPool.SetPoolingEnabled(false); - BulletGlobals.SphereSphereCollisionAlgorithmPool.SetPoolingEnabled(false); - BulletGlobals.SphereTriangleCollisionAlgorithmPool.SetPoolingEnabled(false); - BulletGlobals.GImpactCollisionAlgorithmPool.SetPoolingEnabled(false); - BulletGlobals.GjkEpaSolver2MinkowskiDiffPool.SetPoolingEnabled(false); - BulletGlobals.PersistentManifoldPool.SetPoolingEnabled(false); - BulletGlobals.ManifoldResultPool.SetPoolingEnabled(false); - BulletGlobals.GJKPool.SetPoolingEnabled(false); - BulletGlobals.GIM_ShapeRetrieverPool.SetPoolingEnabled(false); - BulletGlobals.TriangleShapePool.SetPoolingEnabled(false); - BulletGlobals.SphereTriangleDetectorPool.SetPoolingEnabled(false); - BulletGlobals.CompoundLeafCallbackPool.SetPoolingEnabled(false); - BulletGlobals.GjkConvexCastPool.SetPoolingEnabled(false); - BulletGlobals.LocalTriangleSphereCastCallbackPool.SetPoolingEnabled(false); - BulletGlobals.BridgeTriangleRaycastCallbackPool.SetPoolingEnabled(false); - BulletGlobals.BridgeTriangleConcaveRaycastCallbackPool.SetPoolingEnabled(false); - BulletGlobals.BridgeTriangleConvexcastCallbackPool.SetPoolingEnabled(false); - BulletGlobals.MyNodeOverlapCallbackPool.SetPoolingEnabled(false); - BulletGlobals.ClosestRayResultCallbackPool.SetPoolingEnabled(false); - BulletGlobals.DebugDrawcallbackPool.SetPoolingEnabled(false); - - return world; - } - //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL - public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis) - { - Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; - if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) + private sealed class BulletBodyXNA : BulletBody { - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0); - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1); - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2); - } - if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) - { - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3); - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4); - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5); - } - if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL) - { - constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis); - } - return true; - } + public CollisionObject body; + public RigidBody rigidBody { get { return RigidBody.Upcast(body); } } - public override bool PushUpdate(BulletBody pCollisionObject) - { - bool ret = false; - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - RigidBody rb = collisionObject as RigidBody; - if (rb != null) - { - SimMotionState sms = rb.GetMotionState() as SimMotionState; - if (sms != null) + public BulletBodyXNA(uint id, CollisionObject xx) + : base(id) { - IndexedMatrix wt = IndexedMatrix.Identity; - sms.GetWorldTransform(out wt); - sms.SetWorldTransform(ref wt, true); - ret = true; + body = xx; + } + public override bool HasPhysicalBody + { + get { return body != null; } + } + public override void Clear() + { + body = null; + } + public override string AddrString + { + get { return "XNARigidBody"; } } } - return ret; - } - - public override float GetAngularMotionDisc(BulletShape pShape) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - return shape.GetAngularMotionDisc(); - } - public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - return shape.GetContactBreakingThreshold(defaultFactor); - } - public override bool IsCompound(BulletShape pShape) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - return shape.IsCompound(); - } - public override bool IsSoftBody(BulletShape pShape) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - return shape.IsSoftBody(); - } - public override bool IsPolyhedral(BulletShape pShape) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - return shape.IsPolyhedral(); - } - public override bool IsConvex2d(BulletShape pShape) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - return shape.IsConvex2d(); - } - public override bool IsConvex(BulletShape pShape) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - return shape.IsConvex(); - } - public override bool IsNonMoving(BulletShape pShape) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - return shape.IsNonMoving(); - } - public override bool IsConcave(BulletShape pShape) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - return shape.IsConcave(); - } - public override bool IsInfinite(BulletShape pShape) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - return shape.IsInfinite(); - } - public override bool IsNativeShape(BulletShape pShape) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - bool ret; - switch (shape.GetShapeType()) + private sealed class BulletShapeXNA : BulletShape { - case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: - case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: - case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: - case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: - ret = true; - break; - default: - ret = false; - break; - } - return ret; - } - - public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - shape.SetMargin(pMargin); - } - - //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation - public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - IndexedMatrix bodyTransform = new IndexedMatrix(); - bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); - bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W)); - GhostObject gObj = new PairCachingGhostObject(); - gObj.SetWorldTransform(bodyTransform); - CollisionShape shape = (pShape as BulletShapeXNA).shape; - gObj.SetCollisionShape(shape); - gObj.SetUserPointer(pLocalID); - - if (specialCollisionObjects.ContainsKey(pLocalID)) - specialCollisionObjects[pLocalID] = gObj; - else - specialCollisionObjects.Add(pLocalID, gObj); - - // TODO: Add to Special CollisionObjects! - return new BulletBodyXNA(pLocalID, gObj); - } - - public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; - if (pShape == null) - { - collisionObject.SetCollisionShape(new EmptyShape()); - } - else - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - collisionObject.SetCollisionShape(shape); - } - } - public override BulletShape GetCollisionShape(BulletBody pCollisionObject) - { - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - CollisionShape shape = collisionObject.GetCollisionShape(); - return new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); - } - - //(PhysicsScene.World.ptr, nativeShapeData) - public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - CollisionShape shape = null; - switch (pShapeData.Type) - { - case BSPhysicsShapeType.SHAPE_BOX: - shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f)); - break; - case BSPhysicsShapeType.SHAPE_CONE: - shape = new ConeShapeZ(0.5f, 1.0f); - break; - case BSPhysicsShapeType.SHAPE_CYLINDER: - shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f)); - break; - case BSPhysicsShapeType.SHAPE_SPHERE: - shape = new SphereShape(0.5f); - break; - - } - if (shape != null) - { - IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z); - shape.SetMargin(world.WorldSettings.Params.collisionMargin); - shape.SetLocalScaling(ref scaling); - - } - return new BulletShapeXNA(shape, pShapeData.Type); - } - //PhysicsScene.World.ptr, false - public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree) - { - return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND); - } - - public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape) - { - CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape; - return compoundshape.GetNumChildShapes(); - } - //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot - public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot) - { - IndexedMatrix relativeTransform = new IndexedMatrix(); - CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape; - CollisionShape addshape = (paddShape as BulletShapeXNA).shape; - - relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z); - relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W)); - compoundshape.AddChildShape(ref relativeTransform, addshape); - - } - - public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii) - { - CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape; - CollisionShape ret = null; - ret = compoundshape.GetChildShape(pii); - compoundshape.RemoveChildShapeByIndex(pii); - return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); - } - - public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { - - if (cShape == null) - return null; - CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; - CollisionShape shape = compoundShape.GetChildShape(indx); - BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); - - - return retShape; - } - - public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) - { - BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - switch (pin) - { - case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_BOX; - break; - case BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - - case BroadphaseNativeTypes.TETRAHEDRAL_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; - break; - case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_HULL; - break; - case BroadphaseNativeTypes.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - case BroadphaseNativeTypes.CUSTOM_POLYHEDRAL_SHAPE_TYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - //implicit convex shapes - case BroadphaseNativeTypes.IMPLICIT_CONVEX_SHAPES_START_HERE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_SPHERE; - break; - case BroadphaseNativeTypes.MULTI_SPHERE_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - case BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_CAPSULE; - break; - case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_CONE; - break; - case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; - break; - case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_CYLINDER; - break; - case BroadphaseNativeTypes.UNIFORM_SCALING_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - case BroadphaseNativeTypes.MINKOWSKI_SUM_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - case BroadphaseNativeTypes.MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - case BroadphaseNativeTypes.BOX_2D_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - case BroadphaseNativeTypes.CONVEX_2D_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - case BroadphaseNativeTypes.CUSTOM_CONVEX_SHAPE_TYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - //concave shape - case BroadphaseNativeTypes.CONCAVE_SHAPES_START_HERE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy! - case BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_MESH; - break; - case BroadphaseNativeTypes.SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_MESH; - break; - ///used for demo integration FAST/Swift collision library and Bullet - case BroadphaseNativeTypes.FAST_CONCAVE_MESH_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_MESH; - break; - //terrain - case BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_HEIGHTMAP; - break; - ///Used for GIMPACT Trimesh integration - case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_GIMPACT; - break; - ///Multimaterial mesh - case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_MESH; - break; - - case BroadphaseNativeTypes.EMPTY_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - case BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_GROUNDPLANE; - break; - case BroadphaseNativeTypes.CUSTOM_CONCAVE_SHAPE_TYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - case BroadphaseNativeTypes.CONCAVE_SHAPES_END_HERE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - - case BroadphaseNativeTypes.COMPOUND_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_COMPOUND; - break; - - case BroadphaseNativeTypes.SOFTBODY_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_MESH; - break; - case BroadphaseNativeTypes.HFFLUID_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - case BroadphaseNativeTypes.HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - case BroadphaseNativeTypes.INVALID_SHAPE_PROXYTYPE: - ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - break; - } - return ret; - } - - public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ } - public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ } - - public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin) - { - StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight ); - m_planeshape.SetMargin(pcollisionMargin); - m_planeshape.SetUserPointer(pLocalId); - return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); - } - - public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, - Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, - bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) - - { - Generic6DofSpringConstraint constrain = null; - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; - RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; - if (body1 != null && body2 != null) - { - IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); - IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); - IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); - frame1._origin = frame1v; - - IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); - IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); - IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); - frame2._origin = frame2v; - - constrain = new Generic6DofSpringConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); - world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); - - constrain.CalculateTransforms(); - } - - return new BulletConstraintXNA(constrain); - } - - public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, - Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, - bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) - { - HingeConstraint constrain = null; - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; - RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; - if (rb1 != null && rb2 != null) - { - IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); - IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); - IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); - IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); - constrain = new HingeConstraint(rb1, rb2, ref pivotInA, ref pivotInB, ref axisInA, ref axisInB, puseLinearReferenceFrameA); - world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); - } - return new BulletConstraintXNA(constrain); - } - - public override BulletConstraint CreateSliderConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, - Vector3 pframe1, Quaternion pframe1rot, - Vector3 pframe2, Quaternion pframe2rot, - bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) - { - SliderConstraint constrain = null; - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; - RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; - if (rb1 != null && rb2 != null) - { - IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); - IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); - IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); - frame1._origin = frame1v; - - IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); - IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); - IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); - frame2._origin = frame2v; - - constrain = new SliderConstraint(rb1, rb2, ref frame1, ref frame2, puseLinearReferenceFrameA); - world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); - } - return new BulletConstraintXNA(constrain); - } - - public override BulletConstraint CreateConeTwistConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, - Vector3 pframe1, Quaternion pframe1rot, - Vector3 pframe2, Quaternion pframe2rot, - bool pdisableCollisionsBetweenLinkedBodies) - { - ConeTwistConstraint constrain = null; - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; - RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; - if (rb1 != null && rb2 != null) - { - IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); - IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); - IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); - frame1._origin = frame1v; - - IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); - IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); - IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); - frame2._origin = frame2v; - - constrain = new ConeTwistConstraint(rb1, rb2, ref frame1, ref frame2); - world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); - } - return new BulletConstraintXNA(constrain); - } - - public override BulletConstraint CreateGearConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, - Vector3 paxisInA, Vector3 paxisInB, - float pratio, bool pdisableCollisionsBetweenLinkedBodies) - { - Generic6DofConstraint constrain = null; - /* BulletXNA does not have a gear constraint - GearConstraint constrain = null; - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; - RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; - if (rb1 != null && rb2 != null) - { - IndexedVector3 axis1 = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); - IndexedVector3 axis2 = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); - constrain = new GearConstraint(rb1, rb2, ref axis1, ref axis2, pratio); - world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); - } - */ - return new BulletConstraintXNA(constrain); - } - - public override BulletConstraint CreatePoint2PointConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, - Vector3 ppivotInA, Vector3 ppivotInB, - bool pdisableCollisionsBetweenLinkedBodies) - { - Point2PointConstraint constrain = null; - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; - RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; - if (rb1 != null && rb2 != null) - { - IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); - IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); - constrain = new Point2PointConstraint(rb1, rb2, ref pivotInA, ref pivotInB); - world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); - } - return new BulletConstraintXNA(constrain); - } - - public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - CompoundShape compoundshape = new CompoundShape(false); - - compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); - int ii = 1; - - for (int i = 0; i < pHullCount; i++) - { - int vertexCount = (int) pConvHulls[ii]; - - IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]); - IndexedMatrix childTrans = IndexedMatrix.Identity; - childTrans._origin = centroid; - - List virts = new List(); - int ender = ((ii + 4) + (vertexCount*3)); - for (int iii = ii + 4; iii < ender; iii+=3) + public CollisionShape shape; + public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ) + : base() { - - virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); + shape = xx; + shapeType = typ; + } + public override bool HasPhysicalShape + { + get { return shape != null; } + } + public override void Clear() + { + shape = null; + } + public override BulletShape Clone() + { + return new BulletShapeXNA(shape, shapeType); + } + public override bool ReferenceSame(BulletShape other) + { + BulletShapeXNA otheru = other as BulletShapeXNA; + return (otheru != null) && (this.shape == otheru.shape); + + } + public override string AddrString + { + get { return "XNACollisionShape"; } } - ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); - convexShape.SetMargin(world.WorldSettings.Params.collisionMargin); - compoundshape.AddChildShape(ref childTrans, convexShape); - ii += (vertexCount*3 + 4); } - return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); - } - - public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) - { - /* TODO */ return null; - } - - public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) - { - /* TODO */ return null; - } - - public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) - { - /* TODO */ return null; - } - - public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) - { - //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); - - for (int iter = 0; iter < pVerticesCount; iter++) + private sealed class BulletConstraintXNA : BulletConstraint { - if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; - if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; + public TypedConstraint constrain; + public BulletConstraintXNA(TypedConstraint xx) : base() + { + constrain = xx; + } + + public override void Clear() + { + constrain = null; + } + public override bool HasPhysicalConstraint { get { return constrain != null; } } + + // Used for log messages for a unique display of the memory/object allocated to this instance + public override string AddrString + { + get { return "XNAConstraint"; } + } } - ObjectArray indicesarr = new ObjectArray(indices); - ObjectArray vertices = new ObjectArray(verticesAsFloats); - DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - IndexedMesh mesh = new IndexedMesh(); - mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; - mesh.m_numTriangles = pIndicesCount/3; - mesh.m_numVertices = pVerticesCount; - mesh.m_triangleIndexBase = indicesarr; - mesh.m_vertexBase = vertices; - mesh.m_vertexStride = 3; - mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; - mesh.m_triangleIndexStride = 3; + internal int m_maxCollisions; + internal CollisionDesc[] UpdatedCollisions; + internal int LastCollisionDesc = 0; + internal int m_maxUpdatesPerFrame; + internal int LastEntityProperty = 0; - TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); - tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); - BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); - meshShape.SetMargin(world.WorldSettings.Params.collisionMargin); - // world.UpdateSingleAabb(meshShape); - return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); + internal EntityProperties[] UpdatedObjects; + internal Dictionary specialCollisionObjects; - } - public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) - { - // TODO: - return null; - } - public static void DumpRaw(ObjectArrayindices, ObjectArray vertices, int pIndicesCount,int pVerticesCount ) - { + private static int m_collisionsThisFrame; + private BSScene PhysicsScene { get; set; } - String fileName = "objTest3.raw"; - String completePath = System.IO.Path.Combine(Util.configDir(), fileName); - StreamWriter sw = new StreamWriter(completePath); - IndexedMesh mesh = new IndexedMesh(); + public override string BulletEngineName { get { return "BulletXNA"; } } + public override string BulletEngineVersion { get; protected set; } - mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; - mesh.m_numTriangles = pIndicesCount / 3; - mesh.m_numVertices = pVerticesCount; - mesh.m_triangleIndexBase = indices; - mesh.m_vertexBase = vertices; - mesh.m_vertexStride = 3; - mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; - mesh.m_triangleIndexStride = 3; - - TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); - tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); - - - - for (int i = 0; i < pVerticesCount; i++) + public BSAPIXNA(string paramName, BSScene physScene) { - - string s = vertices[indices[i * 3]].ToString("0.0000"); - s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); - s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); - - sw.Write(s + "\n"); + PhysicsScene = physScene; } - sw.Close(); - } - public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount) - { - - String fileName = "objTest6.raw"; - String completePath = System.IO.Path.Combine(Util.configDir(), fileName); - StreamWriter sw = new StreamWriter(completePath); - IndexedMesh mesh = new IndexedMesh(); - - mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; - mesh.m_numTriangles = pIndicesCount / 3; - mesh.m_numVertices = pVerticesCount; - mesh.m_triangleIndexBase = indices; - mesh.m_vertexBase = vertices; - mesh.m_vertexStride = 3; - mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; - mesh.m_triangleIndexStride = 3; - - TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); - tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); - - - sw.WriteLine("Indices"); - sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount)); - for (int iter = 0; iter < indices.Length; iter++) - { - sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter])); - } - sw.WriteLine("VerticesFloats"); - sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount)); - for (int iter = 0; iter < vertices.Length; iter++) - { - sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000"))); - } - - // for (int i = 0; i < pVerticesCount; i++) - // { - // - // string s = vertices[indices[i * 3]].ToString("0.0000"); - // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); - // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); - // - // sw.Write(s + "\n"); - //} - - sw.Close(); - } - - public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, - float scaleFactor, float collisionMargin) - { - const int upAxis = 2; - HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y, - heightMap, scaleFactor, - minHeight, maxHeight, upAxis, - false); - terrainShape.SetMargin(collisionMargin); - terrainShape.SetUseDiamondSubdivision(true); - terrainShape.SetUserPointer(id); - return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN); - } - - public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce) - { - TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain; - bool onOff = ponOff != 0; - bool ret = false; - - switch (tconstrain.GetConstraintType()) - { - case TypedConstraintType.D6_CONSTRAINT_TYPE: - Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint; - constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff; - constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity; - constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce; - ret = true; - break; - } - - - return ret; - - } - - public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, - out int updatedEntityCount, out int collidersCount) - { - /* TODO */ - updatedEntityCount = 0; - collidersCount = 0; - - - int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); - - return ret; - } - - private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, - out int updatedEntityCount, out EntityProperties[] updatedEntities, - out int collidersCount, out CollisionDesc[] colliders) - { - int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities, - out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame); - return epic; - } - - private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, - out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) - { - int numSimSteps = 0; - Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); - Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); - LastEntityProperty=0; - - - - - - - LastCollisionDesc=0; - - updatedEntityCount = 0; - collidersCount = 0; - - - if (pWorld is BulletWorldXNA) + /// + /// + /// + /// + /// + public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody) { DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody body = ((BulletBodyXNA)pBody).rigidBody; + CollisionObject collisionObject = ((BulletBodyXNA)pBody).body; + if (body != null) + world.RemoveRigidBody(body); + else if (collisionObject != null) + world.RemoveCollisionObject(collisionObject); + else + return false; + return true; + } + public override bool ClearCollisionProxyCache(BulletWorld pWorld, BulletBody pBody) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody body = ((BulletBodyXNA)pBody).rigidBody; + CollisionObject collisionObject = ((BulletBodyXNA)pBody).body; + if (body != null && collisionObject != null && collisionObject.GetBroadphaseHandle() != null) + { + world.RemoveCollisionObject(collisionObject); + world.AddCollisionObject(collisionObject); + } + return true; + } + + public override bool AddConstraintToWorld(BulletWorld pWorld, BulletConstraint pConstraint, bool pDisableCollisionsBetweenLinkedObjects) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; + world.AddConstraint(constraint, pDisableCollisionsBetweenLinkedObjects); + + return true; + + } + + public override bool RemoveConstraintFromWorld(BulletWorld pWorld, BulletConstraint pConstraint) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; + world.RemoveConstraint(constraint); + return true; + } + + public override void SetRestitution(BulletBody pCollisionObject, float pRestitution) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + collisionObject.SetRestitution(pRestitution); + } + + public override int GetShapeType(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return (int)shape.GetShapeType(); + } + + public override void SetMargin(BulletShape pShape, float pMargin) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + shape.SetMargin(pMargin); + } + + public override float GetMargin(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.GetMargin(); + } + + public override void SetLocalScaling(BulletShape pShape, Vector3 pScale) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); + shape.SetLocalScaling(ref vec); + } + + public override void SetContactProcessingThreshold(BulletBody pCollisionObject, float contactprocessingthreshold) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + collisionObject.SetContactProcessingThreshold(contactprocessingthreshold); + } + + public override void SetCcdMotionThreshold(BulletBody pCollisionObject, float pccdMotionThreashold) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + collisionObject.SetCcdMotionThreshold(pccdMotionThreashold); + } + + public override void SetCcdSweptSphereRadius(BulletBody pCollisionObject, float pCcdSweptSphereRadius) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + collisionObject.SetCcdSweptSphereRadius(pCcdSweptSphereRadius); + } + + public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z)); + } + + public override CollisionFlags AddToCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags(); + existingcollisionFlags |= pcollisionFlags; + collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); + return (CollisionFlags) (uint) existingcollisionFlags; + } + + public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionObject cbody = (pBody as BulletBodyXNA).body; + RigidBody rbody = cbody as RigidBody; + + // Bullet resets several variables when an object is added to the world. In particular, + // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic + // type. Of course, the collision flags in the broadphase proxy are initialized to default. + IndexedMatrix origPos = cbody.GetWorldTransform(); + if (rbody != null) + { + IndexedVector3 origGrav = rbody.GetGravity(); + world.AddRigidBody(rbody); + rbody.SetGravity(origGrav); + } + else + { + world.AddCollisionObject(cbody); + } + cbody.SetWorldTransform(origPos); + + pBody.ApplyCollisionMask(pWorld.physicsScene); + + //if (body.GetBroadphaseHandle() != null) + // world.UpdateSingleAabb(body); + return true; + } + + public override void ForceActivationState(BulletBody pCollisionObject, ActivationState pActivationState) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + collisionObject.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState); + } + + public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pCollisionObject) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + world.UpdateSingleAabb(collisionObject); + } + + public override void UpdateAabbs(BulletWorld pWorld) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + world.UpdateAabbs(); + } + + public override bool GetForceUpdateAllAabbs(BulletWorld pWorld) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + return world.GetForceUpdateAllAabbs(); + + } + + public override void SetForceUpdateAllAabbs(BulletWorld pWorld, bool pForce) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + world.SetForceUpdateAllAabbs(pForce); + } + + public override bool SetCollisionGroupMask(BulletBody pCollisionObject, uint pGroup, uint pMask) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; + collisionObject.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup; + if ((uint) collisionObject.GetBroadphaseHandle().m_collisionFilterGroup == 0) + return false; + return true; + } + + public override void ClearAllForces(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0); + collisionObject.SetInterpolationLinearVelocity(ref zeroVector); + collisionObject.SetInterpolationAngularVelocity(ref zeroVector); + IndexedMatrix bodytransform = collisionObject.GetWorldTransform(); + + collisionObject.SetInterpolationWorldTransform(ref bodytransform); + + if (collisionObject is RigidBody) + { + RigidBody rigidbody = collisionObject as RigidBody; + rigidbody.SetLinearVelocity(zeroVector); + rigidbody.SetAngularVelocity(zeroVector); + rigidbody.ClearForces(); + } + } + + public override void SetInterpolationAngularVelocity(BulletBody pCollisionObject, Vector3 pVector3) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); + collisionObject.SetInterpolationAngularVelocity(ref vec); + } + + public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z); + body.SetAngularVelocity(ref vec); + } + public override Vector3 GetTotalForce(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = body.GetTotalForce(); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + public override Vector3 GetTotalTorque(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = body.GetTotalTorque(); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = body.GetInvInertiaDiagLocal(); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z); + body.SetInvInertiaDiagLocal(ref iv3); + } + public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z); + IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); + body.ApplyForce(ref forceiv3, ref posiv3); + } + public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z); + IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); + body.ApplyImpulse(ref impiv3, ref posiv3); + } + + public override void ClearForces(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.ClearForces(); + } + + public override void SetTranslation(BulletBody pCollisionObject, Vector3 _position, Quaternion _orientation) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z); + IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z, + _orientation.W); + IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion); + mat._origin = vposition; + collisionObject.SetWorldTransform(mat); + + } + + public override Vector3 GetPosition(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + IndexedVector3 pos = collisionObject.GetInterpolationWorldTransform()._origin; + return new Vector3(pos.X, pos.Y, pos.Z); + } + + public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + IndexedVector3 inertia = IndexedVector3.Zero; + shape.CalculateLocalInertia(pphysMass, out inertia); + return new Vector3(inertia.X, inertia.Y, inertia.Z); + } + + public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + if (body != null) // Can't set mass props on collision object. + { + IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z); + body.SetMassProps(pphysMass, inertia); + } + } + + + public override void SetObjectForce(BulletBody pBody, Vector3 _force) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z); + body.SetTotalForce(ref force); + } + + public override void SetFriction(BulletBody pCollisionObject, float _currentFriction) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + collisionObject.SetFriction(_currentFriction); + } + + public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z); + body.SetLinearVelocity(velocity); + } + + public override void Activate(BulletBody pCollisionObject, bool pforceactivation) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + collisionObject.Activate(pforceactivation); + + } + + public override Quaternion GetOrientation(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + IndexedQuaternion mat = collisionObject.GetInterpolationWorldTransform().GetRotation(); + return new Quaternion(mat.X, mat.Y, mat.Z, mat.W); + } + + public override CollisionFlags RemoveFromCollisionFlags(BulletBody pCollisionObject, CollisionFlags pcollisionFlags) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)collisionObject.GetCollisionFlags(); + existingcollisionFlags &= ~pcollisionFlags; + collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags); + return (CollisionFlags)(uint)existingcollisionFlags; + } + + public override float GetCcdMotionThreshold(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + return collisionObject.GetCcdSquareMotionThreshold(); + } + + public override float GetCcdSweptSphereRadius(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + return collisionObject.GetCcdSweptSphereRadius(); + + } + + public override IntPtr GetUserPointer(BulletBody pCollisionObject) + { + CollisionObject shape = (pCollisionObject as BulletBodyXNA).body; + return (IntPtr)shape.GetUserPointer(); + } + + public override void SetUserPointer(BulletBody pCollisionObject, IntPtr val) + { + CollisionObject shape = (pCollisionObject as BulletBodyXNA).body; + shape.SetUserPointer(val); + } + + public override void SetGravity(BulletBody pBody, Vector3 pGravity) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + if (body != null) // Can't set collisionobject.set gravity + { + IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z); + body.SetGravity(gravity); + } + } + + public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + TypedConstraint constraint = (pConstraint as BulletConstraintXNA).constrain; + world.RemoveConstraint(constraint); + return true; + } + + public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); + IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); + constraint.SetLinearLowerLimit(lowlimit); + constraint.SetLinearUpperLimit(highlimit); + return true; + } + + public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z); + IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z); + constraint.SetAngularLowerLimit(lowlimit); + constraint.SetAngularUpperLimit(highlimit); + return true; + } + + public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + constraint.SetOverrideNumSolverIterations((int)cnt); + } + + public override bool CalculateTransforms(BulletConstraint pConstraint) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + constraint.CalculateTransforms(); + return true; + } + + public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + constraint.SetEnabled((p_2 == 0) ? false : true); + } + + + public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, + bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) + + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; + IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); + IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); + IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); + frame1._origin = frame1v; + + IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); + IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); + IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); + frame2._origin = frame2v; + + Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, + puseLinearReferenceFrameA); + consttr.CalculateTransforms(); + world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); + + return new BulletConstraintXNA(consttr); + } + + public override BulletConstraint Create6DofConstraintFixed(BulletWorld pWorld, BulletBody pBody1, + Vector3 pframe1, Quaternion pframe1rot, + bool pUseLinearReferenceFrameB, bool pdisableCollisionsBetweenLinkedBodies) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; + IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); + IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); + IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); + frame1._origin = frame1v; + + Generic6DofConstraint consttr = new Generic6DofConstraint(body1, ref frame1, pUseLinearReferenceFrameB); + consttr.CalculateTransforms(); + world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies); + + return new BulletConstraintXNA(consttr); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; + IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); + IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0)); + + IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); + IndexedMatrix mat = IndexedMatrix.Identity; + mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z); + frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint; + frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint; + + Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); + consttr.CalculateTransforms(); + world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies); + + return new BulletConstraintXNA(consttr); + } + //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); + public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); + IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); + IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); + frame1._origin = frame1v; + + IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); + IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); + IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); + frame2._origin = frame2v; + constraint.SetFrames(ref frame1, ref frame2); + return true; + } + + public override Vector3 GetLinearVelocity(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = body.GetLinearVelocity(); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + public override Vector3 GetAngularVelocity(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = body.GetAngularVelocity(); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z); + IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + public override void Translate(BulletBody pCollisionObject, Vector3 trans) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + collisionObject.Translate(new IndexedVector3(trans.X,trans.Y,trans.Z)); + } + public override void UpdateDeactivation(BulletBody pBody, float timeStep) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.UpdateDeactivation(timeStep); + } + + public override bool WantsSleeping(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + return body.WantsSleeping(); + } + + public override void SetAngularFactor(BulletBody pBody, float factor) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.SetAngularFactor(factor); + } + + public override Vector3 GetAngularFactor(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 iv3 = body.GetAngularFactor(); + return new Vector3(iv3.X, iv3.Y, iv3.Z); + } + + public override bool IsInWorld(BulletWorld pWorld, BulletBody pCollisionObject) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + return world.IsInWorld(collisionObject); + } + + public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstraint) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain; + body.AddConstraintRef(constrain); + } + + public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstraint) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + TypedConstraint constrain = (pConstraint as BulletConstraintXNA).constrain; + body.RemoveConstraintRef(constrain); + } + + public override BulletConstraint GetConstraintRef(BulletBody pBody, int index) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + return new BulletConstraintXNA(body.GetConstraintRef(index)); + } + + public override int GetNumConstraintRefs(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + return body.GetNumConstraintRefs(); + } + + public override void SetInterpolationLinearVelocity(BulletBody pCollisionObject, Vector3 VehicleVelocity) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z); + collisionObject.SetInterpolationLinearVelocity(ref velocity); + } + + public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + constraint.SetUseFrameOffset((onOff == 0) ? false : true); + return true; + } + //SetBreakingImpulseThreshold(m_constraint.ptr, threshold); + public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold) + { + Generic6DofConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + constraint.SetBreakingImpulseThreshold(threshold); + return true; + } + public override bool HingeSetLimits(BulletConstraint pConstraint, float low, float high, float softness, float bias, float relaxation) + { + HingeConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as HingeConstraint; + if (softness == HINGE_NOT_SPECIFIED) + constraint.SetLimit(low, high); + else + constraint.SetLimit(low, high, softness, bias, relaxation); + return true; + } + public override bool SpringEnable(BulletConstraint pConstraint, int index, float numericTrueFalse) + { + Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; + constraint.EnableSpring(index, (numericTrueFalse == 0f ? false : true)); + return true; + } + + public override bool SpringSetEquilibriumPoint(BulletConstraint pConstraint, int index, float equilibriumPoint) + { + Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; + if (index == SPRING_NOT_SPECIFIED) + { + constraint.SetEquilibriumPoint(); + } + else + { + if (equilibriumPoint == SPRING_NOT_SPECIFIED) + constraint.SetEquilibriumPoint(index); + else + constraint.SetEquilibriumPoint(index, equilibriumPoint); + } + return true; + } + + public override bool SpringSetStiffness(BulletConstraint pConstraint, int index, float stiffness) + { + Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; + constraint.SetStiffness(index, stiffness); + return true; + } + + public override bool SpringSetDamping(BulletConstraint pConstraint, int index, float damping) + { + Generic6DofSpringConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as Generic6DofSpringConstraint; + constraint.SetDamping(index, damping); + return true; + } + + public override bool SliderSetLimits(BulletConstraint pConstraint, int lowerUpper, int linAng, float val) + { + SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; + switch (lowerUpper) + { + case SLIDER_LOWER_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetLowerLinLimit(val); + break; + case SLIDER_ANGULAR: + constraint.SetLowerAngLimit(val); + break; + } + break; + case SLIDER_UPPER_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetUpperLinLimit(val); + break; + case SLIDER_ANGULAR: + constraint.SetUpperAngLimit(val); + break; + } + break; + } + return true; + } + public override bool SliderSet(BulletConstraint pConstraint, int softRestDamp, int dirLimOrtho, int linAng, float val) + { + SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; + switch (softRestDamp) + { + case SLIDER_SET_SOFTNESS: + switch (dirLimOrtho) + { + case SLIDER_SET_DIRECTION: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetSoftnessDirLin(val); break; + case SLIDER_ANGULAR: constraint.SetSoftnessDirAng(val); break; + } + break; + case SLIDER_SET_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetSoftnessLimLin(val); break; + case SLIDER_ANGULAR: constraint.SetSoftnessLimAng(val); break; + } + break; + case SLIDER_SET_ORTHO: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetSoftnessOrthoLin(val); break; + case SLIDER_ANGULAR: constraint.SetSoftnessOrthoAng(val); break; + } + break; + } + break; + case SLIDER_SET_RESTITUTION: + switch (dirLimOrtho) + { + case SLIDER_SET_DIRECTION: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetRestitutionDirLin(val); break; + case SLIDER_ANGULAR: constraint.SetRestitutionDirAng(val); break; + } + break; + case SLIDER_SET_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetRestitutionLimLin(val); break; + case SLIDER_ANGULAR: constraint.SetRestitutionLimAng(val); break; + } + break; + case SLIDER_SET_ORTHO: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetRestitutionOrthoLin(val); break; + case SLIDER_ANGULAR: constraint.SetRestitutionOrthoAng(val); break; + } + break; + } + break; + case SLIDER_SET_DAMPING: + switch (dirLimOrtho) + { + case SLIDER_SET_DIRECTION: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetDampingDirLin(val); break; + case SLIDER_ANGULAR: constraint.SetDampingDirAng(val); break; + } + break; + case SLIDER_SET_LIMIT: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetDampingLimLin(val); break; + case SLIDER_ANGULAR: constraint.SetDampingLimAng(val); break; + } + break; + case SLIDER_SET_ORTHO: + switch (linAng) + { + case SLIDER_LINEAR: constraint.SetDampingOrthoLin(val); break; + case SLIDER_ANGULAR: constraint.SetDampingOrthoAng(val); break; + } + break; + } + break; + } + return true; + } + public override bool SliderMotorEnable(BulletConstraint pConstraint, int linAng, float numericTrueFalse) + { + SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetPoweredLinMotor(numericTrueFalse == 0.0 ? false : true); + break; + case SLIDER_ANGULAR: + constraint.SetPoweredAngMotor(numericTrueFalse == 0.0 ? false : true); + break; + } + return true; + } + public override bool SliderMotor(BulletConstraint pConstraint, int forceVel, int linAng, float val) + { + SliderConstraint constraint = (pConstraint as BulletConstraintXNA).constrain as SliderConstraint; + switch (forceVel) + { + case SLIDER_MOTOR_VELOCITY: + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetTargetLinMotorVelocity(val); + break; + case SLIDER_ANGULAR: + constraint.SetTargetAngMotorVelocity(val); + break; + } + break; + case SLIDER_MAX_MOTOR_FORCE: + switch (linAng) + { + case SLIDER_LINEAR: + constraint.SetMaxLinMotorForce(val); + break; + case SLIDER_ANGULAR: + constraint.SetMaxAngMotorForce(val); + break; + } + break; + } + return true; + } + + //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping); + public override void SetAngularDamping(BulletBody pBody, float angularDamping) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + float lineardamping = body.GetLinearDamping(); + body.SetDamping(lineardamping, angularDamping); + + } + + public override void UpdateInertiaTensor(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + if (body != null) // can't update inertia tensor on CollisionObject + body.UpdateInertiaTensor(); + } + + public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape) + { + CompoundShape shape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape; + shape.RecalculateLocalAabb(); + } + + //BulletSimAPI.GetCollisionFlags(PhysBody.ptr) + public override CollisionFlags GetCollisionFlags(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + uint flags = (uint)collisionObject.GetCollisionFlags(); + return (CollisionFlags) flags; + } + + public override void SetDamping(BulletBody pBody, float pLinear, float pAngular) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.SetDamping(pLinear, pAngular); + } + //PhysBody.ptr, PhysicsScene.Params.deactivationTime); + public override void SetDeactivationTime(BulletBody pCollisionObject, float pDeactivationTime) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + collisionObject.SetDeactivationTime(pDeactivationTime); + } + //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); + public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold); + } + + public override CollisionObjectTypes GetBodyType(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + return (CollisionObjectTypes)(int) collisionObject.GetInternalType(); + } + + public override void ApplyGravity(BulletBody pBody) + { + + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.ApplyGravity(); + } + + public override Vector3 GetGravity(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 gravity = body.GetGravity(); + return new Vector3(gravity.X, gravity.Y, gravity.Z); + } + + public override void SetLinearDamping(BulletBody pBody, float lin_damping) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + float angularDamping = body.GetAngularDamping(); + body.SetDamping(lin_damping, angularDamping); + } + + public override float GetLinearDamping(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + return body.GetLinearDamping(); + } + + public override float GetAngularDamping(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + return body.GetAngularDamping(); + } + + public override float GetLinearSleepingThreshold(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + return body.GetLinearSleepingThreshold(); + } + + public override void ApplyDamping(BulletBody pBody, float timeStep) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.ApplyDamping(timeStep); + } + + public override Vector3 GetLinearFactor(BulletBody pBody) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 linearFactor = body.GetLinearFactor(); + return new Vector3(linearFactor.X, linearFactor.Y, linearFactor.Z); + } + + public override void SetLinearFactor(BulletBody pBody, Vector3 factor) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + body.SetLinearFactor(new IndexedVector3(factor.X, factor.Y, factor.Z)); + } + + public override void SetCenterOfMassByPosRot(BulletBody pBody, Vector3 pos, Quaternion rot) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedQuaternion quat = new IndexedQuaternion(rot.X, rot.Y, rot.Z,rot.W); + IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(quat); + mat._origin = new IndexedVector3(pos.X, pos.Y, pos.Z); + body.SetCenterOfMassTransform( ref mat); + /* TODO: double check this */ + } + + //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum); + public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); + body.ApplyCentralForce(ref fSum); + } + public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); + body.ApplyCentralImpulse(ref fSum); + } + public override void ApplyTorque(BulletBody pBody, Vector3 pfSum) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); + body.ApplyTorque(ref fSum); + } + public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum) + { + RigidBody body = (pBody as BulletBodyXNA).rigidBody; + IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z); + body.ApplyTorqueImpulse(ref fSum); + } + + public override void DestroyObject(BulletWorld pWorld, BulletBody pBody) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionObject co = (pBody as BulletBodyXNA).rigidBody; + RigidBody bo = co as RigidBody; + if (bo == null) + { + + if (world.IsInWorld(co)) + { + world.RemoveCollisionObject(co); + } + } + else + { + + if (world.IsInWorld(bo)) + { + world.RemoveRigidBody(bo); + } + } + if (co != null) + { + if (co.GetUserPointer() != null) + { + uint localId = (uint) co.GetUserPointer(); + if (specialCollisionObjects.ContainsKey(localId)) + { + specialCollisionObjects.Remove(localId); + } + } + } + + } + + public override void Shutdown(BulletWorld pWorld) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + world.Cleanup(); + } + + public override BulletShape DuplicateCollisionShape(BulletWorld pWorld, BulletShape pShape, uint id) + { + CollisionShape shape1 = (pShape as BulletShapeXNA).shape; + + // TODO: Turn this from a reference copy to a Value Copy. + BulletShapeXNA shape2 = new BulletShapeXNA(shape1, BSShapeTypeFromBroadPhaseNativeType(shape1.GetShapeType())); + + return shape2; + } + + public override bool DeleteCollisionShape(BulletWorld pWorld, BulletShape pShape) + { + //TODO: + return false; + } + //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation); + + public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) + { + CollisionWorld world = (pWorld as BulletWorldXNA).world; + IndexedMatrix mat = + IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, + pRawOrientation.Z, pRawOrientation.W)); + mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); + CollisionShape shape = (pShape as BulletShapeXNA).shape; + //UpdateSingleAabb(world, shape); + // TODO: Feed Update array into null + SimMotionState motionState = new SimMotionState(this, pLocalID, mat, null); + RigidBody body = new RigidBody(0,motionState,shape,IndexedVector3.Zero); + RigidBodyConstructionInfo constructionInfo = new RigidBodyConstructionInfo(0, motionState, shape, IndexedVector3.Zero) + { + m_mass = 0 + }; + /* + m_mass = mass; + m_motionState =motionState; + m_collisionShape = collisionShape; + m_localInertia = localInertia; + m_linearDamping = 0f; + m_angularDamping = 0f; + m_friction = 0.5f; + m_restitution = 0f; + m_linearSleepingThreshold = 0.8f; + m_angularSleepingThreshold = 1f; + m_additionalDamping = false; + m_additionalDampingFactor = 0.005f; + m_additionalLinearDampingThresholdSqr = 0.01f; + m_additionalAngularDampingThresholdSqr = 0.01f; + m_additionalAngularDampingFactor = 0.01f; + m_startWorldTransform = IndexedMatrix.Identity; + */ + body.SetUserPointer(pLocalID); + + return new BulletBodyXNA(pLocalID, body); + } + + + public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) + { + + IndexedMatrix mat = + IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y, + pRawOrientation.Z, pRawOrientation.W)); + mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); + + CollisionShape shape = (pShape as BulletShapeXNA).shape; + + // TODO: Feed Update array into null + RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero); + body.SetWorldTransform(mat); + body.SetUserPointer(pLocalID); + return new BulletBodyXNA(pLocalID, body); + } + //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); + public override CollisionFlags SetCollisionFlags(BulletBody pCollisionObject, CollisionFlags collisionFlags) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + collisionObject.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags); + return (CollisionFlags)collisionObject.GetCollisionFlags(); + } + + public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) + { + + /* TODO */ + return Vector3.Zero; + } + public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; } + public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; } + public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; } + public override bool IsStaticObject(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + return collisionObject.IsStaticObject(); + + } + public override bool IsKinematicObject(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + return collisionObject.IsKinematicObject(); + } + public override bool IsStaticOrKinematicObject(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + return collisionObject.IsStaticOrKinematicObject(); + } + public override bool HasContactResponse(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + return collisionObject.HasContactResponse(); + } + public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; } + public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ } + public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; } + public override bool IsActive(BulletBody pBody) { /* TODO */ return false; } + public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; } + public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; } + public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ } + public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; } + + //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); + public override void SetHitFraction(BulletBody pCollisionObject, float pHitFraction) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + collisionObject.SetHitFraction(pHitFraction); + } + //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale); + public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z); + CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight); + capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin); + capsuleShapeZ.SetLocalScaling(ref scale); + + return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ; + } + + public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, + int maxCollisions, ref CollisionDesc[] collisionArray, + int maxUpdates, ref EntityProperties[] updateArray + ) + { + + UpdatedObjects = updateArray; + UpdatedCollisions = collisionArray; + /* TODO */ + ConfigurationParameters[] configparms = new ConfigurationParameters[1]; + configparms[0] = parms; + Vector3 worldExtent = maxPosition; + m_maxCollisions = maxCollisions; + m_maxUpdatesPerFrame = maxUpdates; + specialCollisionObjects = new Dictionary(); + + return new BulletWorldXNA(1, PhysicsScene, BSAPIXNA.Initialize2(worldExtent, configparms, maxCollisions, ref collisionArray, maxUpdates, ref updateArray, null)); + } + + private static DiscreteDynamicsWorld Initialize2(Vector3 worldExtent, + ConfigurationParameters[] o, + int mMaxCollisionsPerFrame, ref CollisionDesc[] collisionArray, + int mMaxUpdatesPerFrame, ref EntityProperties[] updateArray, + object mDebugLogCallbackHandle) + { + CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData(); + + p.angularDamping = BSParam.AngularDamping; + p.defaultFriction = o[0].defaultFriction; + p.defaultFriction = o[0].defaultFriction; + p.defaultDensity = o[0].defaultDensity; + p.defaultRestitution = o[0].defaultRestitution; + p.collisionMargin = o[0].collisionMargin; + p.gravity = o[0].gravity; + + p.linearDamping = BSParam.LinearDamping; + p.angularDamping = BSParam.AngularDamping; + p.deactivationTime = BSParam.DeactivationTime; + p.linearSleepingThreshold = BSParam.LinearSleepingThreshold; + p.angularSleepingThreshold = BSParam.AngularSleepingThreshold; + p.ccdMotionThreshold = BSParam.CcdMotionThreshold; + p.ccdSweptSphereRadius = BSParam.CcdSweptSphereRadius; + p.contactProcessingThreshold = BSParam.ContactProcessingThreshold; + + p.terrainImplementation = BSParam.TerrainImplementation; + p.terrainFriction = BSParam.TerrainFriction; + + p.terrainHitFraction = BSParam.TerrainHitFraction; + p.terrainRestitution = BSParam.TerrainRestitution; + p.terrainCollisionMargin = BSParam.TerrainCollisionMargin; + + p.avatarFriction = BSParam.AvatarFriction; + p.avatarStandingFriction = BSParam.AvatarStandingFriction; + p.avatarDensity = BSParam.AvatarDensity; + p.avatarRestitution = BSParam.AvatarRestitution; + p.avatarCapsuleWidth = BSParam.AvatarCapsuleWidth; + p.avatarCapsuleDepth = BSParam.AvatarCapsuleDepth; + p.avatarCapsuleHeight = BSParam.AvatarCapsuleHeight; + p.avatarContactProcessingThreshold = BSParam.AvatarContactProcessingThreshold; + + p.vehicleAngularDamping = BSParam.VehicleAngularDamping; + + p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize; + p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize; + p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation; + p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs; + p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder; + p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands; + p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching; + p.numberOfSolverIterations = o[0].numberOfSolverIterations; + + p.linksetImplementation = BSParam.LinksetImplementation; + p.linkConstraintUseFrameOffset = BSParam.NumericBool(BSParam.LinkConstraintUseFrameOffset); + p.linkConstraintEnableTransMotor = BSParam.NumericBool(BSParam.LinkConstraintEnableTransMotor); + p.linkConstraintTransMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; + p.linkConstraintTransMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; + p.linkConstraintERP = BSParam.LinkConstraintERP; + p.linkConstraintCFM = BSParam.LinkConstraintCFM; + p.linkConstraintSolverIterations = BSParam.LinkConstraintSolverIterations; + p.physicsLoggingFrames = o[0].physicsLoggingFrames; + DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo(); + + DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration(); + CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci); + + + if (p.maxPersistantManifoldPoolSize > 0) + cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize; + if (p.shouldDisableContactPoolDynamicAllocation !=0) + m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION); + //if (p.maxCollisionAlgorithmPoolSize >0 ) + + DbvtBroadphase m_broadphase = new DbvtBroadphase(); + //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0); + //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256); + + //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true); + m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback()); + + SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver(); + + DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci); + world.LastCollisionDesc = 0; world.LastEntityProperty = 0; - numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep); - + + world.WorldSettings.Params = p; + world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0); + world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD; + if (p.shouldRandomizeSolverOrder != 0) + world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER; + + world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0); + //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port + + if (p.shouldEnableFrictionCaching != 0) + world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING; + + if (p.numberOfSolverIterations > 0) + world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations; + + + world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping; + world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution; + world.GetSolverInfo().m_globalCfm = 0.0f; + world.GetSolverInfo().m_tau = 0.6f; + world.GetSolverInfo().m_friction = 0.3f; + world.GetSolverInfo().m_maxErrorReduction = 20f; + world.GetSolverInfo().m_numIterations = 10; + world.GetSolverInfo().m_erp = 0.2f; + world.GetSolverInfo().m_erp2 = 0.1f; + world.GetSolverInfo().m_sor = 1.0f; + world.GetSolverInfo().m_splitImpulse = false; + world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f; + world.GetSolverInfo().m_linearSlop = 0.0f; + world.GetSolverInfo().m_warmstartingFactor = 0.85f; + world.GetSolverInfo().m_restingContactRestitutionThreshold = 2; + world.SetForceUpdateAllAabbs(true); + + //BSParam.TerrainImplementation = 0; + world.SetGravity(new IndexedVector3(0,0,p.gravity)); + + // Turn off Pooling since globals and pooling are bad for threading. + BulletGlobals.VoronoiSimplexSolverPool.SetPoolingEnabled(false); + BulletGlobals.SubSimplexConvexCastPool.SetPoolingEnabled(false); + BulletGlobals.ManifoldPointPool.SetPoolingEnabled(false); + BulletGlobals.CastResultPool.SetPoolingEnabled(false); + BulletGlobals.SphereShapePool.SetPoolingEnabled(false); + BulletGlobals.DbvtNodePool.SetPoolingEnabled(false); + BulletGlobals.SingleRayCallbackPool.SetPoolingEnabled(false); + BulletGlobals.SubSimplexClosestResultPool.SetPoolingEnabled(false); + BulletGlobals.GjkPairDetectorPool.SetPoolingEnabled(false); + BulletGlobals.DbvtTreeColliderPool.SetPoolingEnabled(false); + BulletGlobals.SingleSweepCallbackPool.SetPoolingEnabled(false); + BulletGlobals.BroadphaseRayTesterPool.SetPoolingEnabled(false); + BulletGlobals.ClosestNotMeConvexResultCallbackPool.SetPoolingEnabled(false); + BulletGlobals.GjkEpaPenetrationDepthSolverPool.SetPoolingEnabled(false); + BulletGlobals.ContinuousConvexCollisionPool.SetPoolingEnabled(false); + BulletGlobals.DbvtStackDataBlockPool.SetPoolingEnabled(false); + + BulletGlobals.BoxBoxCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.CompoundCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.ConvexConcaveCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.ConvexConvexAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.ConvexPlaneAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.SphereBoxCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.SphereSphereCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.SphereTriangleCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.GImpactCollisionAlgorithmPool.SetPoolingEnabled(false); + BulletGlobals.GjkEpaSolver2MinkowskiDiffPool.SetPoolingEnabled(false); + BulletGlobals.PersistentManifoldPool.SetPoolingEnabled(false); + BulletGlobals.ManifoldResultPool.SetPoolingEnabled(false); + BulletGlobals.GJKPool.SetPoolingEnabled(false); + BulletGlobals.GIM_ShapeRetrieverPool.SetPoolingEnabled(false); + BulletGlobals.TriangleShapePool.SetPoolingEnabled(false); + BulletGlobals.SphereTriangleDetectorPool.SetPoolingEnabled(false); + BulletGlobals.CompoundLeafCallbackPool.SetPoolingEnabled(false); + BulletGlobals.GjkConvexCastPool.SetPoolingEnabled(false); + BulletGlobals.LocalTriangleSphereCastCallbackPool.SetPoolingEnabled(false); + BulletGlobals.BridgeTriangleRaycastCallbackPool.SetPoolingEnabled(false); + BulletGlobals.BridgeTriangleConcaveRaycastCallbackPool.SetPoolingEnabled(false); + BulletGlobals.BridgeTriangleConvexcastCallbackPool.SetPoolingEnabled(false); + BulletGlobals.MyNodeOverlapCallbackPool.SetPoolingEnabled(false); + BulletGlobals.ClosestRayResultCallbackPool.SetPoolingEnabled(false); + BulletGlobals.DebugDrawcallbackPool.SetPoolingEnabled(false); + + return world; + } + //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL + public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis) + { + Generic6DofConstraint constrain = (pConstraint as BulletConstraintXNA).constrain as Generic6DofConstraint; + if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) + { + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0); + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1); + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2); + } + if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL) + { + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3); + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4); + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5); + } + if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL) + { + constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis); + } + return true; + } + + public override bool PushUpdate(BulletBody pCollisionObject) + { + bool ret = false; + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + RigidBody rb = collisionObject as RigidBody; + if (rb != null) + { + SimMotionState sms = rb.GetMotionState() as SimMotionState; + if (sms != null) + { + IndexedMatrix wt = IndexedMatrix.Identity; + sms.GetWorldTransform(out wt); + sms.SetWorldTransform(ref wt, true); + ret = true; + } + } + return ret; + + } + + public override float GetAngularMotionDisc(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.GetAngularMotionDisc(); + } + public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.GetContactBreakingThreshold(defaultFactor); + } + public override bool IsCompound(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsCompound(); + } + public override bool IsSoftBody(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsSoftBody(); + } + public override bool IsPolyhedral(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsPolyhedral(); + } + public override bool IsConvex2d(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsConvex2d(); + } + public override bool IsConvex(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsConvex(); + } + public override bool IsNonMoving(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsNonMoving(); + } + public override bool IsConcave(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsConcave(); + } + public override bool IsInfinite(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + return shape.IsInfinite(); + } + public override bool IsNativeShape(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + bool ret; + switch (shape.GetShapeType()) + { + case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: + case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: + case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: + case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: + ret = true; + break; + default: + ret = false; + break; + } + return ret; + } + + public override void SetShapeCollisionMargin(BulletShape pShape, float pMargin) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + shape.SetMargin(pMargin); + } + + //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation + public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + IndexedMatrix bodyTransform = new IndexedMatrix(); + bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z); + bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W)); + GhostObject gObj = new PairCachingGhostObject(); + gObj.SetWorldTransform(bodyTransform); + CollisionShape shape = (pShape as BulletShapeXNA).shape; + gObj.SetCollisionShape(shape); + gObj.SetUserPointer(pLocalID); + + if (specialCollisionObjects.ContainsKey(pLocalID)) + specialCollisionObjects[pLocalID] = gObj; + else + specialCollisionObjects.Add(pLocalID, gObj); + + // TODO: Add to Special CollisionObjects! + return new BulletBodyXNA(pLocalID, gObj); + } + + public override void SetCollisionShape(BulletWorld pWorld, BulletBody pCollisionObject, BulletShape pShape) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).body; + if (pShape == null) + { + collisionObject.SetCollisionShape(new EmptyShape()); + } + else + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + collisionObject.SetCollisionShape(shape); + } + } + public override BulletShape GetCollisionShape(BulletBody pCollisionObject) + { + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + CollisionShape shape = collisionObject.GetCollisionShape(); + return new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); + } + + //(PhysicsScene.World.ptr, nativeShapeData) + public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionShape shape = null; + switch (pShapeData.Type) + { + case BSPhysicsShapeType.SHAPE_BOX: + shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f)); + break; + case BSPhysicsShapeType.SHAPE_CONE: + shape = new ConeShapeZ(0.5f, 1.0f); + break; + case BSPhysicsShapeType.SHAPE_CYLINDER: + shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f)); + break; + case BSPhysicsShapeType.SHAPE_SPHERE: + shape = new SphereShape(0.5f); + break; + + } + if (shape != null) + { + IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z); + shape.SetMargin(world.WorldSettings.Params.collisionMargin); + shape.SetLocalScaling(ref scaling); + + } + return new BulletShapeXNA(shape, pShapeData.Type); + } + //PhysicsScene.World.ptr, false + public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree) + { + return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND); + } + + public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape) + { + CompoundShape compoundshape = (pCompoundShape as BulletShapeXNA).shape as CompoundShape; + return compoundshape.GetNumChildShapes(); + } + //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot + public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot) + { + IndexedMatrix relativeTransform = new IndexedMatrix(); + CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape; + CollisionShape addshape = (paddShape as BulletShapeXNA).shape; + + relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z); + relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W)); + compoundshape.AddChildShape(ref relativeTransform, addshape); + + } + + public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii) + { + CompoundShape compoundshape = (pCShape as BulletShapeXNA).shape as CompoundShape; + CollisionShape ret = null; + ret = compoundshape.GetChildShape(pii); + compoundshape.RemoveChildShapeByIndex(pii); + return new BulletShapeXNA(ret, BSShapeTypeFromBroadPhaseNativeType(ret.GetShapeType())); + } + + public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { + + if (cShape == null) + return null; + CompoundShape compoundShape = (cShape as BulletShapeXNA).shape as CompoundShape; + CollisionShape shape = compoundShape.GetChildShape(indx); + BulletShape retShape = new BulletShapeXNA(shape, BSShapeTypeFromBroadPhaseNativeType(shape.GetShapeType())); + + + return retShape; + } + + public BSPhysicsShapeType BSShapeTypeFromBroadPhaseNativeType(BroadphaseNativeTypes pin) + { + BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + switch (pin) + { + case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_BOX; + break; + case BroadphaseNativeTypes.TRIANGLE_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + + case BroadphaseNativeTypes.TETRAHEDRAL_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; + break; + case BroadphaseNativeTypes.CONVEX_HULL_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_HULL; + break; + case BroadphaseNativeTypes.CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.CUSTOM_POLYHEDRAL_SHAPE_TYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + //implicit convex shapes + case BroadphaseNativeTypes.IMPLICIT_CONVEX_SHAPES_START_HERE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_SPHERE; + break; + case BroadphaseNativeTypes.MULTI_SPHERE_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.CAPSULE_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_CAPSULE; + break; + case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_CONE; + break; + case BroadphaseNativeTypes.CONVEX_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_CONVEXHULL; + break; + case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_CYLINDER; + break; + case BroadphaseNativeTypes.UNIFORM_SCALING_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.MINKOWSKI_SUM_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.BOX_2D_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.CONVEX_2D_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.CUSTOM_CONVEX_SHAPE_TYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + //concave shape + case BroadphaseNativeTypes.CONCAVE_SHAPES_START_HERE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy! + case BroadphaseNativeTypes.TRIANGLE_MESH_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_MESH; + break; + case BroadphaseNativeTypes.SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_MESH; + break; + ///used for demo integration FAST/Swift collision library and Bullet + case BroadphaseNativeTypes.FAST_CONCAVE_MESH_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_MESH; + break; + //terrain + case BroadphaseNativeTypes.TERRAIN_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_HEIGHTMAP; + break; + ///Used for GIMPACT Trimesh integration + case BroadphaseNativeTypes.GIMPACT_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_GIMPACT; + break; + ///Multimaterial mesh + case BroadphaseNativeTypes.MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_MESH; + break; + + case BroadphaseNativeTypes.EMPTY_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.STATIC_PLANE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_GROUNDPLANE; + break; + case BroadphaseNativeTypes.CUSTOM_CONCAVE_SHAPE_TYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.CONCAVE_SHAPES_END_HERE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + + case BroadphaseNativeTypes.COMPOUND_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_COMPOUND; + break; + + case BroadphaseNativeTypes.SOFTBODY_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_MESH; + break; + case BroadphaseNativeTypes.HFFLUID_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + case BroadphaseNativeTypes.INVALID_SHAPE_PROXYTYPE: + ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + break; + } + return ret; + } + + public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ } + public override void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb) { /* TODO */ } + + public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin) + { + StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight ); + m_planeshape.SetMargin(pcollisionMargin); + m_planeshape.SetUserPointer(pLocalId); + return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE); + } + + public override BulletConstraint Create6DofSpringConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, + bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) + + { + Generic6DofSpringConstraint constrain = null; + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody body1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody body2 = (pBody2 as BulletBodyXNA).rigidBody; + if (body1 != null && body2 != null) + { + IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); + IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); + IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); + frame1._origin = frame1v; + + IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); + IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); + IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); + frame2._origin = frame2v; + + constrain = new Generic6DofSpringConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA); + world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); + + constrain.CalculateTransforms(); + } + + return new BulletConstraintXNA(constrain); + } + + public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, + bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) + { + HingeConstraint constrain = null; + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; + if (rb1 != null && rb2 != null) + { + IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); + IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); + IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); + IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); + constrain = new HingeConstraint(rb1, rb2, ref pivotInA, ref pivotInB, ref axisInA, ref axisInB, puseLinearReferenceFrameA); + world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); + } + return new BulletConstraintXNA(constrain); + } + + public override BulletConstraint CreateSliderConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 pframe1, Quaternion pframe1rot, + Vector3 pframe2, Quaternion pframe2rot, + bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies) + { + SliderConstraint constrain = null; + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; + if (rb1 != null && rb2 != null) + { + IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); + IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); + IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); + frame1._origin = frame1v; + + IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); + IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); + IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); + frame2._origin = frame2v; + + constrain = new SliderConstraint(rb1, rb2, ref frame1, ref frame2, puseLinearReferenceFrameA); + world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); + } + return new BulletConstraintXNA(constrain); + } + + public override BulletConstraint CreateConeTwistConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 pframe1, Quaternion pframe1rot, + Vector3 pframe2, Quaternion pframe2rot, + bool pdisableCollisionsBetweenLinkedBodies) + { + ConeTwistConstraint constrain = null; + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; + if (rb1 != null && rb2 != null) + { + IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z); + IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W); + IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot); + frame1._origin = frame1v; + + IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z); + IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W); + IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot); + frame2._origin = frame2v; + + constrain = new ConeTwistConstraint(rb1, rb2, ref frame1, ref frame2); + world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); + } + return new BulletConstraintXNA(constrain); + } + + public override BulletConstraint CreateGearConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 paxisInA, Vector3 paxisInB, + float pratio, bool pdisableCollisionsBetweenLinkedBodies) + { + Generic6DofConstraint constrain = null; + /* BulletXNA does not have a gear constraint + GearConstraint constrain = null; + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; + if (rb1 != null && rb2 != null) + { + IndexedVector3 axis1 = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z); + IndexedVector3 axis2 = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z); + constrain = new GearConstraint(rb1, rb2, ref axis1, ref axis2, pratio); + world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); + } + */ + return new BulletConstraintXNA(constrain); + } + + public override BulletConstraint CreatePoint2PointConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, + Vector3 ppivotInA, Vector3 ppivotInB, + bool pdisableCollisionsBetweenLinkedBodies) + { + Point2PointConstraint constrain = null; + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + RigidBody rb1 = (pBody1 as BulletBodyXNA).rigidBody; + RigidBody rb2 = (pBody2 as BulletBodyXNA).rigidBody; + if (rb1 != null && rb2 != null) + { + IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z); + IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z); + constrain = new Point2PointConstraint(rb1, rb2, ref pivotInA, ref pivotInB); + world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies); + } + return new BulletConstraintXNA(constrain); + } + + public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CompoundShape compoundshape = new CompoundShape(false); + + compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin); + int ii = 1; + + for (int i = 0; i < pHullCount; i++) + { + int vertexCount = (int) pConvHulls[ii]; + + IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]); + IndexedMatrix childTrans = IndexedMatrix.Identity; + childTrans._origin = centroid; + + List virts = new List(); + int ender = ((ii + 4) + (vertexCount*3)); + for (int iii = ii + 4; iii < ender; iii+=3) + { + + virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2])); + } + ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount); + convexShape.SetMargin(world.WorldSettings.Params.collisionMargin); + compoundshape.AddChildShape(ref childTrans, convexShape); + ii += (vertexCount*3 + 4); + } + + return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL); + } + + public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms) + { + /* TODO */ return null; + } + + public override BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape) + { + /* TODO */ return null; + } + + public override BulletShape CreateConvexHullShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) + { + /* TODO */ return null; + } + + public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) + { + //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount); + + for (int iter = 0; iter < pVerticesCount; iter++) + { + if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0; + if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0; + } + + ObjectArray indicesarr = new ObjectArray(indices); + ObjectArray vertices = new ObjectArray(verticesAsFloats); + DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount); + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + IndexedMesh mesh = new IndexedMesh(); + mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; + mesh.m_numTriangles = pIndicesCount/3; + mesh.m_numVertices = pVerticesCount; + mesh.m_triangleIndexBase = indicesarr; + mesh.m_vertexBase = vertices; + mesh.m_vertexStride = 3; + mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; + mesh.m_triangleIndexStride = 3; + + TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); + tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); + BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true); + meshShape.SetMargin(world.WorldSettings.Params.collisionMargin); + // world.UpdateSingleAabb(meshShape); + return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH); + + } + public override BulletShape CreateGImpactShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats) + { + // TODO: + return null; + } + public static void DumpRaw(ObjectArrayindices, ObjectArray vertices, int pIndicesCount,int pVerticesCount ) + { + + String fileName = "objTest3.raw"; + String completePath = System.IO.Path.Combine(Util.configDir(), fileName); + StreamWriter sw = new StreamWriter(completePath); + IndexedMesh mesh = new IndexedMesh(); + + mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; + mesh.m_numTriangles = pIndicesCount / 3; + mesh.m_numVertices = pVerticesCount; + mesh.m_triangleIndexBase = indices; + mesh.m_vertexBase = vertices; + mesh.m_vertexStride = 3; + mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; + mesh.m_triangleIndexStride = 3; + + TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); + tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); + + + + for (int i = 0; i < pVerticesCount; i++) + { + + string s = vertices[indices[i * 3]].ToString("0.0000"); + s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); + s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); + + sw.Write(s + "\n"); + } + + sw.Close(); + } + public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount) + { + + String fileName = "objTest6.raw"; + String completePath = System.IO.Path.Combine(Util.configDir(), fileName); + StreamWriter sw = new StreamWriter(completePath); + IndexedMesh mesh = new IndexedMesh(); + + mesh.m_indexType = PHY_ScalarType.PHY_INTEGER; + mesh.m_numTriangles = pIndicesCount / 3; + mesh.m_numVertices = pVerticesCount; + mesh.m_triangleIndexBase = indices; + mesh.m_vertexBase = vertices; + mesh.m_vertexStride = 3; + mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT; + mesh.m_triangleIndexStride = 3; + + TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray(); + tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER); + + + sw.WriteLine("Indices"); + sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount)); + for (int iter = 0; iter < indices.Length; iter++) + { + sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter])); + } + sw.WriteLine("VerticesFloats"); + sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount)); + for (int iter = 0; iter < vertices.Length; iter++) + { + sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000"))); + } + + // for (int i = 0; i < pVerticesCount; i++) + // { + // + // string s = vertices[indices[i * 3]].ToString("0.0000"); + // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000"); + // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000"); + // + // sw.Write(s + "\n"); + //} + + sw.Close(); + } + + public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, + float scaleFactor, float collisionMargin) + { + const int upAxis = 2; + HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y, + heightMap, scaleFactor, + minHeight, maxHeight, upAxis, + false); + terrainShape.SetMargin(collisionMargin); + terrainShape.SetUseDiamondSubdivision(true); + terrainShape.SetUserPointer(id); + return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN); + } + + public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce) + { + TypedConstraint tconstrain = (pConstraint as BulletConstraintXNA).constrain; + bool onOff = ponOff != 0; + bool ret = false; + + switch (tconstrain.GetConstraintType()) + { + case TypedConstraintType.D6_CONSTRAINT_TYPE: + Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint; + constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff; + constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity; + constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce; + ret = true; + break; + } + + + return ret; + + } + + public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, + out int updatedEntityCount, out int collidersCount) + { + /* TODO */ + updatedEntityCount = 0; + collidersCount = 0; + + + int ret = PhysicsStep2(world,timeStep,maxSubSteps,fixedTimeStep,out updatedEntityCount,out world.physicsScene.m_updateArray, out collidersCount, out world.physicsScene.m_collisionArray); + + return ret; + } + + private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep, + out int updatedEntityCount, out EntityProperties[] updatedEntities, + out int collidersCount, out CollisionDesc[] colliders) + { + int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities, + out collidersCount, out colliders, m_maxCollisions, m_maxUpdatesPerFrame); + return epic; + } + + private int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, + out EntityProperties[] updatedEntities, out int collidersCount, out CollisionDesc[] colliders, int maxCollisions, int maxUpdates) + { + int numSimSteps = 0; + Array.Clear(UpdatedObjects, 0, UpdatedObjects.Length); + Array.Clear(UpdatedCollisions, 0, UpdatedCollisions.Length); + LastEntityProperty=0; + + + + + + + LastCollisionDesc=0; + + updatedEntityCount = 0; + collidersCount = 0; + + + if (pWorld is BulletWorldXNA) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + + world.LastCollisionDesc = 0; + world.LastEntityProperty = 0; + numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep); + + PersistentManifold contactManifold; + CollisionObject objA; + CollisionObject objB; + ManifoldPoint manifoldPoint; + PairCachingGhostObject pairCachingGhostObject; + + m_collisionsThisFrame = 0; + int numManifolds = world.GetDispatcher().GetNumManifolds(); + for (int j = 0; j < numManifolds; j++) + { + contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j); + int numContacts = contactManifold.GetNumContacts(); + if (numContacts == 0) + continue; + + objA = contactManifold.GetBody0() as CollisionObject; + objB = contactManifold.GetBody1() as CollisionObject; + + manifoldPoint = contactManifold.GetContactPoint(0); + //IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB(); + // IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A + + RecordCollision(this, objA, objB, manifoldPoint.GetPositionWorldOnB(), -manifoldPoint.m_normalWorldOnB, manifoldPoint.GetDistance()); + m_collisionsThisFrame ++; + if (m_collisionsThisFrame >= 9999999) + break; + + + } + + foreach (GhostObject ghostObject in specialCollisionObjects.Values) + { + pairCachingGhostObject = ghostObject as PairCachingGhostObject; + if (pairCachingGhostObject != null) + { + RecordGhostCollisions(pairCachingGhostObject); + } + + } + + + updatedEntityCount = LastEntityProperty; + updatedEntities = UpdatedObjects; + + collidersCount = LastCollisionDesc; + colliders = UpdatedCollisions; + + + } + else + { + //if (updatedEntities is null) + //updatedEntities = new List(); + //updatedEntityCount = 0; + + + //collidersCount = 0; + + updatedEntities = new EntityProperties[0]; + + + colliders = new CollisionDesc[0]; + + } + return numSimSteps; + } + public void RecordGhostCollisions(PairCachingGhostObject obj) + { + IOverlappingPairCache cache = obj.GetOverlappingPairCache(); + ObjectArray pairs = cache.GetOverlappingPairArray(); + + DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; + PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); + BroadphasePair collisionPair; PersistentManifold contactManifold; + CollisionObject objA; CollisionObject objB; - ManifoldPoint manifoldPoint; - PairCachingGhostObject pairCachingGhostObject; - - m_collisionsThisFrame = 0; - int numManifolds = world.GetDispatcher().GetNumManifolds(); - for (int j = 0; j < numManifolds; j++) + + ManifoldPoint pt; + + int numPairs = pairs.Count; + + for (int i = 0; i < numPairs; i++) { - contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j); - int numContacts = contactManifold.GetNumContacts(); - if (numContacts == 0) - continue; - - objA = contactManifold.GetBody0() as CollisionObject; - objB = contactManifold.GetBody1() as CollisionObject; - - manifoldPoint = contactManifold.GetContactPoint(0); - //IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB(); - // IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A - - RecordCollision(this, objA, objB, manifoldPoint.GetPositionWorldOnB(), -manifoldPoint.m_normalWorldOnB, manifoldPoint.GetDistance()); - m_collisionsThisFrame ++; - if (m_collisionsThisFrame >= 9999999) + manifoldArray.Clear(); + if (LastCollisionDesc < UpdatedCollisions.Length) break; - - - } - - foreach (GhostObject ghostObject in specialCollisionObjects.Values) - { - pairCachingGhostObject = ghostObject as PairCachingGhostObject; - if (pairCachingGhostObject != null) + collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); + if (collisionPair == null) + continue; + + collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); + for (int j = 0; j < manifoldArray.Count; j++) { - RecordGhostCollisions(pairCachingGhostObject); - } - - } - - - updatedEntityCount = LastEntityProperty; - updatedEntities = UpdatedObjects; - - collidersCount = LastCollisionDesc; - colliders = UpdatedCollisions; - - - } - else - { - //if (updatedEntities is null) - //updatedEntities = new List(); - //updatedEntityCount = 0; - - - //collidersCount = 0; - - updatedEntities = new EntityProperties[0]; - - - colliders = new CollisionDesc[0]; - - } - return numSimSteps; - } - public void RecordGhostCollisions(PairCachingGhostObject obj) - { - IOverlappingPairCache cache = obj.GetOverlappingPairCache(); - ObjectArray pairs = cache.GetOverlappingPairArray(); - - DiscreteDynamicsWorld world = (PhysicsScene.World as BulletWorldXNA).world; - PersistentManifoldArray manifoldArray = new PersistentManifoldArray(); - BroadphasePair collisionPair; - PersistentManifold contactManifold; - - CollisionObject objA; - CollisionObject objB; - - ManifoldPoint pt; - - int numPairs = pairs.Count; - - for (int i = 0; i < numPairs; i++) - { - manifoldArray.Clear(); - if (LastCollisionDesc < UpdatedCollisions.Length) - break; - collisionPair = world.GetPairCache().FindPair(pairs[i].m_pProxy0, pairs[i].m_pProxy1); - if (collisionPair == null) - continue; - - collisionPair.m_algorithm.GetAllContactManifolds(manifoldArray); - for (int j = 0; j < manifoldArray.Count; j++) - { - contactManifold = manifoldArray[j]; - int numContacts = contactManifold.GetNumContacts(); - objA = contactManifold.GetBody0() as CollisionObject; - objB = contactManifold.GetBody1() as CollisionObject; - for (int p = 0; p < numContacts; p++) - { - pt = contactManifold.GetContactPoint(p); - if (pt.GetDistance() < 0.0f) + contactManifold = manifoldArray[j]; + int numContacts = contactManifold.GetNumContacts(); + objA = contactManifold.GetBody0() as CollisionObject; + objB = contactManifold.GetBody1() as CollisionObject; + for (int p = 0; p < numContacts; p++) { - RecordCollision(this, objA, objB, pt.GetPositionWorldOnA(), -pt.m_normalWorldOnB,pt.GetDistance()); - break; + pt = contactManifold.GetContactPoint(p); + if (pt.GetDistance() < 0.0f) + { + RecordCollision(this, objA, objB, pt.GetPositionWorldOnA(), -pt.m_normalWorldOnB,pt.GetDistance()); + break; + } } } } + } - - } - private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) - { - - IndexedVector3 contactNormal = norm; - if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && - (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) + private static void RecordCollision(BSAPIXNA world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm, float penetration) { - return; - } - uint idA = (uint)objA.GetUserPointer(); - uint idB = (uint)objB.GetUserPointer(); - if (idA > idB) - { - uint temp = idA; - idA = idB; - idB = temp; - contactNormal = -contactNormal; - } - - //ulong collisionID = ((ulong) idA << 32) | idB; - - CollisionDesc cDesc = new CollisionDesc() - { - aID = idA, - bID = idB, - point = new Vector3(contact.X,contact.Y,contact.Z), - normal = new Vector3(contactNormal.X,contactNormal.Y,contactNormal.Z), - penetration = penetration - - }; - if (world.LastCollisionDesc < world.UpdatedCollisions.Length) - world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc); - m_collisionsThisFrame++; - - - } - private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject) - { - EntityProperties ent = new EntityProperties(); - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; - IndexedMatrix transform = collisionObject.GetWorldTransform(); - IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity(); - IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity(); - IndexedQuaternion rotation = transform.GetRotation(); - ent.Acceleration = Vector3.Zero; - ent.ID = (uint)collisionObject.GetUserPointer(); - ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z); - ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W); - ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z); - ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z); - return ent; - } - - public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ - return false; } - - public override Vector3 GetLocalScaling(BulletShape pShape) - { - CollisionShape shape = (pShape as BulletShapeXNA).shape; - IndexedVector3 scale = shape.GetLocalScaling(); - return new Vector3(scale.X,scale.Y,scale.Z); - } - - public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe) - { - DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; - if (world != null) - { - if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) + + IndexedVector3 contactNormal = norm; + if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 && + (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0) { - CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; - - IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); - IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); - using ( - ClosestNotMeRayResultCallback rayCallback = - new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) - ) - { - world.RayTest(ref rOrigin, ref rEnd, rayCallback); - if (rayCallback.HasHit()) - { - IndexedVector3 hitLocation = rayCallback.m_hitPointWorld; - } - return rayCallback.HasHit(); - } - } + return; + } + uint idA = (uint)objA.GetUserPointer(); + uint idB = (uint)objB.GetUserPointer(); + if (idA > idB) + { + uint temp = idA; + idA = idB; + idB = temp; + contactNormal = -contactNormal; + } + + //ulong collisionID = ((ulong) idA << 32) | idB; + + CollisionDesc cDesc = new CollisionDesc() + { + aID = idA, + bID = idB, + point = new Vector3(contact.X,contact.Y,contact.Z), + normal = new Vector3(contactNormal.X,contactNormal.Y,contactNormal.Z), + penetration = penetration + + }; + if (world.LastCollisionDesc < world.UpdatedCollisions.Length) + world.UpdatedCollisions[world.LastCollisionDesc++] = (cDesc); + m_collisionsThisFrame++; + + + } + private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pCollisionObject) + { + EntityProperties ent = new EntityProperties(); + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + CollisionObject collisionObject = (pCollisionObject as BulletBodyXNA).rigidBody; + IndexedMatrix transform = collisionObject.GetWorldTransform(); + IndexedVector3 LinearVelocity = collisionObject.GetInterpolationLinearVelocity(); + IndexedVector3 AngularVelocity = collisionObject.GetInterpolationAngularVelocity(); + IndexedQuaternion rotation = transform.GetRotation(); + ent.Acceleration = Vector3.Zero; + ent.ID = (uint)collisionObject.GetUserPointer(); + ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z); + ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W); + ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z); + ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z); + return ent; + } + + public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ + return false; } + + public override Vector3 GetLocalScaling(BulletShape pShape) + { + CollisionShape shape = (pShape as BulletShapeXNA).shape; + IndexedVector3 scale = shape.GetLocalScaling(); + return new Vector3(scale.X,scale.Y,scale.Z); + } + + public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe) + { + DiscreteDynamicsWorld world = (pWorld as BulletWorldXNA).world; + if (world != null) + { + if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody) + { + CollisionObject AvoidBody = (NotMe as BulletBodyXNA).body; + + IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z); + IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight); + using ( + ClosestNotMeRayResultCallback rayCallback = + new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody) + ) + { + world.RayTest(ref rOrigin, ref rEnd, rayCallback); + if (rayCallback.HasHit()) + { + IndexedVector3 hitLocation = rayCallback.m_hitPointWorld; + } + return rayCallback.HasHit(); + } + } + } + return false; + } + + public override SweepHit ConvexSweepTest2(BulletWorld world, BulletBody obj, Vector3 from, Vector3 to, float margin) { + return new SweepHit(); + } + + public override RaycastHit RayTest2(BulletWorld world, Vector3 from, Vector3 to, uint filterGroup, uint filterMask) { + return new RaycastHit(); } - return false; } - public override SweepHit ConvexSweepTest2(BulletWorld world, BulletBody obj, Vector3 from, Vector3 to, float margin) { - return new SweepHit(); - } - - public override RaycastHit RayTest2(BulletWorld world, Vector3 from, Vector3 to, uint filterGroup, uint filterMask) { - return new RaycastHit(); - } -} - - - public class SimMotionState : DefaultMotionState { @@ -2521,6 +2525,7 @@ private sealed class BulletConstraintXNA : BulletConstraint { SetWorldTransform(ref worldTrans, false); } + public void SetWorldTransform(ref IndexedMatrix worldTrans, bool force) { m_xform = worldTrans; @@ -2550,7 +2555,7 @@ private sealed class BulletConstraintXNA : BulletConstraint && (m_properties.Velocity != m_lastProperties.Velocity || m_properties.RotationalVelocity != m_lastProperties.RotationalVelocity)) - // If Velocity and AngularVelocity are non-zero but have changed, send an update. + // If Velocity and AngularVelocity are non-zero but have changed, send an update. || !AlmostEqual(ref m_properties.Velocity, ref m_lastProperties.Velocity, VELOCITY_TOLERANCE) || !AlmostEqual(ref m_properties.RotationalVelocity, ref m_lastProperties.RotationalVelocity, @@ -2571,10 +2576,12 @@ private sealed class BulletConstraintXNA : BulletConstraint } + public override void SetRigidBody(RigidBody body) { Rigidbody = body; } + internal static bool AlmostEqual(ref Vector3 v1, ref Vector3 v2, float nEpsilon) { return @@ -2591,7 +2598,5 @@ private sealed class BulletConstraintXNA : BulletConstraint (((v1.Z - nEpsilon) < v2.Z) && (v2.Z < (v1.Z + nEpsilon))) && (((v1.W - nEpsilon) < v2.W) && (v2.W < (v1.W + nEpsilon))); } - } } - diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs index 4e9216db30..925f526f2b 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorAvatarMove.cs @@ -37,423 +37,424 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -public class BSActorAvatarMove : BSActor -{ - BSVMotor m_velocityMotor; - - // Set to true if we think we're going up stairs. - // This state is remembered because collisions will turn on and off as we go up stairs. - int m_walkingUpStairs; - // The amount the step up is applying. Used to smooth stair walking. - float m_lastStepUp; - - // There are times the velocity or force is set but we don't want to inforce - // stationary until some tick in the future and the real velocity drops. - int m_waitingForLowVelocityForStationary = 0; - - public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName) - : base(physicsScene, pObj, actorName) + public class BSActorAvatarMove : BSActor { - m_velocityMotor = null; - m_walkingUpStairs = 0; - m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID); - } + BSVMotor m_velocityMotor; - // BSActor.isActive - public override bool isActive - { - get { return Enabled && m_controllingPrim.IsPhysicallyActive; } - } + // Set to true if we think we're going up stairs. + // This state is remembered because collisions will turn on and off as we go up stairs. + int m_walkingUpStairs; + // The amount the step up is applying. Used to smooth stair walking. + float m_lastStepUp; - // Release any connections and resources used by the actor. - // BSActor.Dispose() - public override void Dispose() - { - base.SetEnabled(false); - DeactivateAvatarMove(); - } + // There are times the velocity or force is set but we don't want to inforce + // stationary until some tick in the future and the real velocity drops. + int m_waitingForLowVelocityForStationary = 0; - // Called when physical parameters (properties set in Bullet) need to be re-applied. - // Called at taint-time. - // BSActor.Refresh() - public override void Refresh() - { - m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID); - - // If the object is physically active, add the hoverer prestep action - if (isActive) + public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) { - ActivateAvatarMove(); + m_velocityMotor = null; + m_walkingUpStairs = 0; + m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID); } - else + + // BSActor.isActive + public override bool isActive { + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() + { + base.SetEnabled(false); DeactivateAvatarMove(); } - } - // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). - // Register a prestep action to restore physical requirements before the next simulation step. - // Called at taint-time. - // BSActor.RemoveDependencies() - public override void RemoveDependencies() - { - // Nothing to do for the hoverer since it is all software at pre-step action time. - } + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() + { + m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID); + + // If the object is physically active, add the hoverer prestep action + if (isActive) + { + ActivateAvatarMove(); + } + else + { + DeactivateAvatarMove(); + } + } - // Usually called when target velocity changes to set the current velocity and the target - // into the movement motor. - public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime) - { - m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate() + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveDependencies() + public override void RemoveDependencies() + { + // Nothing to do for the hoverer since it is all software at pre-step action time. + } + + // Usually called when target velocity changes to set the current velocity and the target + // into the movement motor. + public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime) + { + m_physicsScene.TaintedObject(inTaintTime, m_controllingPrim.LocalID, "BSActorAvatarMove.setVelocityAndTarget", delegate() + { + if (m_velocityMotor != null) + { + m_velocityMotor.Reset(); + m_velocityMotor.SetTarget(targ); + m_velocityMotor.SetCurrent(vel); + m_velocityMotor.Enabled = true; + m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,SetVelocityAndTarget,vel={1}, targ={2}", + m_controllingPrim.LocalID, vel, targ); + m_waitingForLowVelocityForStationary = 0; + } + }); + } + + public void SuppressStationayCheckUntilLowVelocity() + { + m_waitingForLowVelocityForStationary = 1; + } + + public void SuppressStationayCheckUntilLowVelocity(int waitTicks) + { + m_waitingForLowVelocityForStationary = waitTicks; + } + + // If a movement motor has not been created, create one and start the movement + private void ActivateAvatarMove() + { + if (m_velocityMotor == null) + { + // Infinite decay and timescale values so motor only changes current to target values. + m_velocityMotor = new BSVMotor("BSCharacter.Velocity", + 0.2f, // time scale + BSMotor.Infinite, // decay time scale + 1f // efficiency + ); + m_velocityMotor.ErrorZeroThreshold = BSParam.AvatarStopZeroThreshold; + // m_velocityMotor.PhysicsScene = m_controllingPrim.PhysScene; // DEBUG DEBUG so motor will output detail log messages. + SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); + + m_physicsScene.BeforeStep += Mover; + m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty; + + m_walkingUpStairs = 0; + m_waitingForLowVelocityForStationary = 0; + } + } + + private void DeactivateAvatarMove() { if (m_velocityMotor != null) { - m_velocityMotor.Reset(); - m_velocityMotor.SetTarget(targ); - m_velocityMotor.SetCurrent(vel); - m_velocityMotor.Enabled = true; - m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,SetVelocityAndTarget,vel={1}, targ={2}", - m_controllingPrim.LocalID, vel, targ); - m_waitingForLowVelocityForStationary = 0; + m_controllingPrim.OnPreUpdateProperty -= Process_OnPreUpdateProperty; + m_physicsScene.BeforeStep -= Mover; + m_velocityMotor = null; } - }); - } - - public void SuppressStationayCheckUntilLowVelocity() - { - m_waitingForLowVelocityForStationary = 1; - } - public void SuppressStationayCheckUntilLowVelocity(int waitTicks) - { - m_waitingForLowVelocityForStationary = waitTicks; - } - - // If a movement motor has not been created, create one and start the movement - private void ActivateAvatarMove() - { - if (m_velocityMotor == null) - { - // Infinite decay and timescale values so motor only changes current to target values. - m_velocityMotor = new BSVMotor("BSCharacter.Velocity", - 0.2f, // time scale - BSMotor.Infinite, // decay time scale - 1f // efficiency - ); - m_velocityMotor.ErrorZeroThreshold = BSParam.AvatarStopZeroThreshold; - // m_velocityMotor.PhysicsScene = m_controllingPrim.PhysScene; // DEBUG DEBUG so motor will output detail log messages. - SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */); - - m_physicsScene.BeforeStep += Mover; - m_controllingPrim.OnPreUpdateProperty += Process_OnPreUpdateProperty; - - m_walkingUpStairs = 0; - m_waitingForLowVelocityForStationary = 0; } - } - private void DeactivateAvatarMove() - { - if (m_velocityMotor != null) + // Called just before the simulation step. + private void Mover(float timeStep) { - m_controllingPrim.OnPreUpdateProperty -= Process_OnPreUpdateProperty; - m_physicsScene.BeforeStep -= Mover; - m_velocityMotor = null; - } - } - - // Called just before the simulation step. - private void Mover(float timeStep) - { - // Don't do movement while the object is selected. - if (!isActive) - return; - - // TODO: Decide if the step parameters should be changed depending on the avatar's - // state (flying, colliding, ...). There is code in ODE to do this. - - // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity - // specified for the avatar is the one that should be used. For falling, if the avatar - // is not flying and is not colliding then it is presumed to be falling and the Z - // component is not fooled with (thus allowing gravity to do its thing). - // When the avatar is standing, though, the user has specified a velocity of zero and - // the avatar should be standing. But if the avatar is pushed by something in the world - // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to - // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity - // errors can creap in and the avatar will slowly float off in some direction. - // So, the problem is that, when an avatar is standing, we cannot tell creaping error - // from real pushing. - // The code below uses whether the collider is static or moving to decide whether to zero motion. - - m_velocityMotor.Step(timeStep); - m_controllingPrim.IsStationary = false; - - // If we're not supposed to be moving, make sure things are zero. - if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero) - { - // The avatar shouldn't be moving - m_velocityMotor.Zero(); - - if (m_controllingPrim.IsColliding) + // Don't do movement while the object is selected. + if (!isActive) + return; + + // TODO: Decide if the step parameters should be changed depending on the avatar's + // state (flying, colliding, ...). There is code in ODE to do this. + + // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity + // specified for the avatar is the one that should be used. For falling, if the avatar + // is not flying and is not colliding then it is presumed to be falling and the Z + // component is not fooled with (thus allowing gravity to do its thing). + // When the avatar is standing, though, the user has specified a velocity of zero and + // the avatar should be standing. But if the avatar is pushed by something in the world + // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to + // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity + // errors can creap in and the avatar will slowly float off in some direction. + // So, the problem is that, when an avatar is standing, we cannot tell creaping error + // from real pushing. + // The code below uses whether the collider is static or moving to decide whether to zero motion. + + m_velocityMotor.Step(timeStep); + m_controllingPrim.IsStationary = false; + + // If we're not supposed to be moving, make sure things are zero. + if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero) { - // if colliding with something stationary and we're not doing volume detect . - if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.ColliderIsVolumeDetect) + // The avatar shouldn't be moving + m_velocityMotor.Zero(); + + if (m_controllingPrim.IsColliding) { - if (m_waitingForLowVelocityForStationary-- <= 0) + // if colliding with something stationary and we're not doing volume detect . + if (!m_controllingPrim.ColliderIsMoving && !m_controllingPrim.ColliderIsVolumeDetect) { - // if waiting for velocity to drop and it has finally dropped, we can be stationary - // m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,waitingForLowVelocity {1}", - // m_controllingPrim.LocalID, m_waitingForLowVelocityForStationary); - if (m_controllingPrim.RawVelocity.LengthSquared() < BSParam.AvatarStopZeroThresholdSquared) + if (m_waitingForLowVelocityForStationary-- <= 0) { - m_waitingForLowVelocityForStationary = 0; + // if waiting for velocity to drop and it has finally dropped, we can be stationary + // m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,waitingForLowVelocity {1}", + // m_controllingPrim.LocalID, m_waitingForLowVelocityForStationary); + if (m_controllingPrim.RawVelocity.LengthSquared() < BSParam.AvatarStopZeroThresholdSquared) + { + m_waitingForLowVelocityForStationary = 0; + } + } + if (m_waitingForLowVelocityForStationary <= 0) + { + m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID); + m_controllingPrim.IsStationary = true; + m_controllingPrim.ZeroMotion(true /* inTaintTime */); + } + else + { + m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,waitingForLowVel,rawvel={1}", + m_controllingPrim.LocalID, m_controllingPrim.RawVelocity.Length()); } } - if (m_waitingForLowVelocityForStationary <= 0) + + // Standing has more friction on the ground + if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction) { - m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID); - m_controllingPrim.IsStationary = true; + m_controllingPrim.Friction = BSParam.AvatarStandingFriction; + m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); + } + } + else + { + if (m_controllingPrim.Flying) + { + // Flying and not colliding and velocity nearly zero. m_controllingPrim.ZeroMotion(true /* inTaintTime */); } else { - m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,waitingForLowVel,rawvel={1}", - m_controllingPrim.LocalID, m_controllingPrim.RawVelocity.Length()); + //We are falling but are not touching any keys make sure not falling too fast + if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity) + { + + OMV.Vector3 slowingForce = new OMV.Vector3(0f, 0f, BSParam.AvatarTerminalVelocity - m_controllingPrim.RawVelocity.Z) * m_controllingPrim.Mass; + m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, slowingForce); + } + } } - - // Standing has more friction on the ground - if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction) - { - m_controllingPrim.Friction = BSParam.AvatarStandingFriction; - m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); - } + + m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2},isStationary={3}", + m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding,m_controllingPrim.IsStationary); } else { + // Supposed to be moving. + OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue; + + if (m_controllingPrim.Friction != BSParam.AvatarFriction) + { + // Probably starting to walk. Set friction to moving friction. + m_controllingPrim.Friction = BSParam.AvatarFriction; + m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); + } + + // 'm_velocityMotor is used for walking, flying, and jumping and will thus have the correct values + // for Z. But in come cases it must be over-ridden. Like when falling or jumping. + + float realVelocityZ = m_controllingPrim.RawVelocity.Z; + + // If not flying and falling, we over-ride the stepping motor so we can fall to the ground + if (!m_controllingPrim.Flying && realVelocityZ < 0) + { + // Can't fall faster than this + if (realVelocityZ < BSParam.AvatarTerminalVelocity) + { + realVelocityZ = BSParam.AvatarTerminalVelocity; + } + + stepVelocity.Z = realVelocityZ; + } + // m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,DEBUG,motorCurrent={1},realZ={2},flying={3},collid={4},jFrames={5}", + // m_controllingPrim.LocalID, m_velocityMotor.CurrentValue, realVelocityZ, m_controllingPrim.Flying, m_controllingPrim.IsColliding, m_jumpFrames); + + //Alicia: Maintain minimum height when flying. + // SL has a flying effect that keeps the avatar flying above the ground by some margin if (m_controllingPrim.Flying) { - // Flying and not colliding and velocity nearly zero. - m_controllingPrim.ZeroMotion(true /* inTaintTime */); - } - else - { - //We are falling but are not touching any keys make sure not falling too fast - if (m_controllingPrim.RawVelocity.Z < BSParam.AvatarTerminalVelocity) + float hover_height = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition) + + BSParam.AvatarFlyingGroundMargin; + + if( m_controllingPrim.Position.Z < hover_height) { - - OMV.Vector3 slowingForce = new OMV.Vector3(0f, 0f, BSParam.AvatarTerminalVelocity - m_controllingPrim.RawVelocity.Z) * m_controllingPrim.Mass; - m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, slowingForce); + m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,addingUpforceForGroundMargin,height={1},hoverHeight={2}", + m_controllingPrim.LocalID, m_controllingPrim.Position.Z, hover_height); + stepVelocity.Z += BSParam.AvatarFlyingGroundUpForce; } - } + + // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. + OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass; + + // Add special movement force to allow avatars to walk up stepped surfaces. + moveForce += WalkUpStairs(); + + m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", + m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce); + m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce); } - - m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2},isStationary={3}", - m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding,m_controllingPrim.IsStationary); - } - else - { - // Supposed to be moving. - OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue; - - if (m_controllingPrim.Friction != BSParam.AvatarFriction) - { - // Probably starting to walk. Set friction to moving friction. - m_controllingPrim.Friction = BSParam.AvatarFriction; - m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction); - } - - // 'm_velocityMotor is used for walking, flying, and jumping and will thus have the correct values - // for Z. But in come cases it must be over-ridden. Like when falling or jumping. - - float realVelocityZ = m_controllingPrim.RawVelocity.Z; - - // If not flying and falling, we over-ride the stepping motor so we can fall to the ground - if (!m_controllingPrim.Flying && realVelocityZ < 0) - { - // Can't fall faster than this - if (realVelocityZ < BSParam.AvatarTerminalVelocity) - { - realVelocityZ = BSParam.AvatarTerminalVelocity; - } - - stepVelocity.Z = realVelocityZ; - } - // m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,DEBUG,motorCurrent={1},realZ={2},flying={3},collid={4},jFrames={5}", - // m_controllingPrim.LocalID, m_velocityMotor.CurrentValue, realVelocityZ, m_controllingPrim.Flying, m_controllingPrim.IsColliding, m_jumpFrames); - - //Alicia: Maintain minimum height when flying. - // SL has a flying effect that keeps the avatar flying above the ground by some margin - if (m_controllingPrim.Flying) - { - float hover_height = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition) - + BSParam.AvatarFlyingGroundMargin; - - if( m_controllingPrim.Position.Z < hover_height) - { - m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,addingUpforceForGroundMargin,height={1},hoverHeight={2}", - m_controllingPrim.LocalID, m_controllingPrim.Position.Z, hover_height); - stepVelocity.Z += BSParam.AvatarFlyingGroundUpForce; - } - } - - // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. - OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass; - - // Add special movement force to allow avatars to walk up stepped surfaces. - moveForce += WalkUpStairs(); - - m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", - m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce); - m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce); - } - } - - // Called just as the property update is received from the physics engine. - // Do any mode necessary for avatar movement. - private void Process_OnPreUpdateProperty(ref EntityProperties entprop) - { - // Don't change position if standing on a stationary object. - if (m_controllingPrim.IsStationary) - { - entprop.Position = m_controllingPrim.RawPosition; - entprop.Velocity = OMV.Vector3.Zero; - m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation); } - } - - // Decide if the character is colliding with a low object and compute a force to pop the - // avatar up so it can walk up and over the low objects. - private OMV.Vector3 WalkUpStairs() - { - OMV.Vector3 ret = OMV.Vector3.Zero; - - m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}", - m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying, - m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z); - - // Check for stairs climbing if colliding, not flying and moving forward - if ( m_controllingPrim.IsColliding - && !m_controllingPrim.Flying - && m_controllingPrim.TargetVelocitySpeed > 0.1f ) + // Called just as the property update is received from the physics engine. + // Do any mode necessary for avatar movement. + private void Process_OnPreUpdateProperty(ref EntityProperties entprop) { - // The range near the character's feet where we will consider stairs - // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f; - // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off - // from the height. Revisit size and this computation when height is scaled properly. - float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - BSParam.AvatarStepGroundFudge; - float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; - - // Look for a collision point that is near the character's feet and is oriented the same as the charactor is. - // Find the highest 'good' collision. - OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero; - foreach (KeyValuePair kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList) + // Don't change position if standing on a stationary object. + if (m_controllingPrim.IsStationary) { - // Don't care about collisions with the terrain - if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID) + entprop.Position = m_controllingPrim.RawPosition; + entprop.Velocity = OMV.Vector3.Zero; + m_physicsScene.PE.SetTranslation(m_controllingPrim.PhysBody, entprop.Position, entprop.Rotation); + } + + } + + // Decide if the character is colliding with a low object and compute a force to pop the + // avatar up so it can walk up and over the low objects. + private OMV.Vector3 WalkUpStairs() + { + OMV.Vector3 ret = OMV.Vector3.Zero; + + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}", + m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying, + m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z); + + // Check for stairs climbing if colliding, not flying and moving forward + if ( m_controllingPrim.IsColliding + && !m_controllingPrim.Flying + && m_controllingPrim.TargetVelocitySpeed > 0.1f ) + { + // The range near the character's feet where we will consider stairs + // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f; + // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off + // from the height. Revisit size and this computation when height is scaled properly. + float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - BSParam.AvatarStepGroundFudge; + float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight; + + // Look for a collision point that is near the character's feet and is oriented the same as the charactor is. + // Find the highest 'good' collision. + OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero; + foreach (KeyValuePair kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList) { - BSPhysObject collisionObject; - if (m_physicsScene.PhysObjects.TryGetValue(kvp.Key, out collisionObject)) + // Don't care about collisions with the terrain + if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID) { - if (!collisionObject.IsVolumeDetect) + BSPhysObject collisionObject; + if (m_physicsScene.PhysObjects.TryGetValue(kvp.Key, out collisionObject)) { - OMV.Vector3 touchPosition = kvp.Value.Position; - m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", - m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); - if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) + if (!collisionObject.IsVolumeDetect) { - // This contact is within the 'near the feet' range. - // The step is presumed to be more or less vertical. Thus the Z component should - // be nearly horizontal. - OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation; - OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); - const float PIOver2 = 1.571f; // Used to make unit vector axis into approx radian angles - // m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,avNormal={1},colNormal={2},diff={3}", - // m_controllingPrim.LocalID, directionFacing, touchNormal, - // Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)) ); - if ((Math.Abs(directionFacing.Z) * PIOver2) < BSParam.AvatarStepAngle - && (Math.Abs(touchNormal.Z) * PIOver2) < BSParam.AvatarStepAngle) + OMV.Vector3 touchPosition = kvp.Value.Position; + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}", + m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition); + if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax) { - // The normal should be our contact point to the object so it is pointing away - // thus the difference between our facing orientation and the normal should be small. - float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); - if (diff < BSParam.AvatarStepApproachFactor) + // This contact is within the 'near the feet' range. + // The step is presumed to be more or less vertical. Thus the Z component should + // be nearly horizontal. + OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation; + OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal); + const float PIOver2 = 1.571f; // Used to make unit vector axis into approx radian angles + // m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,avNormal={1},colNormal={2},diff={3}", + // m_controllingPrim.LocalID, directionFacing, touchNormal, + // Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)) ); + if ((Math.Abs(directionFacing.Z) * PIOver2) < BSParam.AvatarStepAngle + && (Math.Abs(touchNormal.Z) * PIOver2) < BSParam.AvatarStepAngle) { - if (highestTouchPosition.Z < touchPosition.Z) - highestTouchPosition = touchPosition; + // The normal should be our contact point to the object so it is pointing away + // thus the difference between our facing orientation and the normal should be small. + float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal)); + if (diff < BSParam.AvatarStepApproachFactor) + { + if (highestTouchPosition.Z < touchPosition.Z) + highestTouchPosition = touchPosition; + } } } } } } } - } - m_walkingUpStairs = 0; - // If there is a good step sensing, move the avatar over the step. - if (highestTouchPosition != OMV.Vector3.Zero) - { - // Remember that we are going up stairs. This is needed because collisions - // will stop when we move up so this smoothes out that effect. - m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps; - - m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin; - ret = ComputeStairCorrection(m_lastStepUp); - m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}", - m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret); - } - } - else - { - // If we used to be going up stairs but are not now, smooth the case where collision goes away while - // we are bouncing up the stairs. - if (m_walkingUpStairs > 0) - { - m_walkingUpStairs--; - ret = ComputeStairCorrection(m_lastStepUp); - } - } - - return ret; - } - - private OMV.Vector3 ComputeStairCorrection(float stepUp) - { - OMV.Vector3 ret = OMV.Vector3.Zero; - OMV.Vector3 displacement = OMV.Vector3.Zero; - - if (stepUp > 0f) - { - // Found the stairs contact point. Push up a little to raise the character. - if (BSParam.AvatarStepForceFactor > 0f) - { - float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; - ret = new OMV.Vector3(0f, 0f, upForce); - } - - // Also move the avatar up for the new height - if (BSParam.AvatarStepUpCorrectionFactor > 0f) - { - // Move the avatar up related to the height of the collision - displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor); - m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; + m_walkingUpStairs = 0; + // If there is a good step sensing, move the avatar over the step. + if (highestTouchPosition != OMV.Vector3.Zero) + { + // Remember that we are going up stairs. This is needed because collisions + // will stop when we move up so this smoothes out that effect. + m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps; + + m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin; + ret = ComputeStairCorrection(m_lastStepUp); + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}", + m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret); + } } else { - if (BSParam.AvatarStepUpCorrectionFactor < 0f) + // If we used to be going up stairs but are not now, smooth the case where collision goes away while + // we are bouncing up the stairs. + if (m_walkingUpStairs > 0) { - // Move the avatar up about the specified step height - displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight); - m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; + m_walkingUpStairs--; + ret = ComputeStairCorrection(m_lastStepUp); } } - m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,stepUp={1},isp={2},force={3}", - m_controllingPrim.LocalID, stepUp, displacement, ret); - + + return ret; + } + + private OMV.Vector3 ComputeStairCorrection(float stepUp) + { + OMV.Vector3 ret = OMV.Vector3.Zero; + OMV.Vector3 displacement = OMV.Vector3.Zero; + + if (stepUp > 0f) + { + // Found the stairs contact point. Push up a little to raise the character. + if (BSParam.AvatarStepForceFactor > 0f) + { + float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor; + ret = new OMV.Vector3(0f, 0f, upForce); + } + + // Also move the avatar up for the new height + if (BSParam.AvatarStepUpCorrectionFactor > 0f) + { + // Move the avatar up related to the height of the collision + displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor); + m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; + } + else + { + if (BSParam.AvatarStepUpCorrectionFactor < 0f) + { + // Move the avatar up about the specified step height + displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight); + m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement; + } + } + m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,stepUp={1},isp={2},force={3}", + m_controllingPrim.LocalID, stepUp, displacement, ret); + + } + return ret; } - return ret; } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs index 7ff171ed08..c1c002797f 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorHover.cs @@ -36,139 +36,139 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -public class BSActorHover : BSActor -{ - private BSFMotor m_hoverMotor; - - public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName) - : base(physicsScene, pObj, actorName) + public class BSActorHover : BSActor { - m_hoverMotor = null; - m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID); - } + private BSFMotor m_hoverMotor; - // BSActor.isActive - public override bool isActive - { - get { return Enabled; } - } - - // Release any connections and resources used by the actor. - // BSActor.Dispose() - public override void Dispose() - { - Enabled = false; - DeactivateHover(); - } - - // Called when physical parameters (properties set in Bullet) need to be re-applied. - // Called at taint-time. - // BSActor.Refresh() - public override void Refresh() - { - m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID); - - // If not active any more, turn me off - if (!m_controllingPrim.HoverActive) + public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) { - SetEnabled(false); + m_hoverMotor = null; + m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID); } - // If the object is physically active, add the hoverer prestep action - if (isActive) + // BSActor.isActive + public override bool isActive { - ActivateHover(); + get { return Enabled; } } - else + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() { + Enabled = false; DeactivateHover(); } - } - // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). - // Register a prestep action to restore physical requirements before the next simulation step. - // Called at taint-time. - // BSActor.RemoveDependencies() - public override void RemoveDependencies() - { - // Nothing to do for the hoverer since it is all software at pre-step action time. - } - - // If a hover motor has not been created, create one and start the hovering. - private void ActivateHover() - { - if (m_hoverMotor == null) + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() { - // Turning the target on - m_hoverMotor = new BSFMotor("BSActorHover", - m_controllingPrim.HoverTau, // timeScale - BSMotor.Infinite, // decay time scale - 1f // efficiency - ); - m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); + m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID); + + // If not active any more, turn me off + if (!m_controllingPrim.HoverActive) + { + SetEnabled(false); + } + + // If the object is physically active, add the hoverer prestep action + if (isActive) + { + ActivateHover(); + } + else + { + DeactivateHover(); + } + } + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveDependencies() + public override void RemoveDependencies() + { + // Nothing to do for the hoverer since it is all software at pre-step action time. + } + + // If a hover motor has not been created, create one and start the hovering. + private void ActivateHover() + { + if (m_hoverMotor == null) + { + // Turning the target on + m_hoverMotor = new BSFMotor("BSActorHover", + m_controllingPrim.HoverTau, // timeScale + BSMotor.Infinite, // decay time scale + 1f // efficiency + ); + m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); + m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z); + m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. + + m_physicsScene.BeforeStep += Hoverer; + } + } + + private void DeactivateHover() + { + if (m_hoverMotor != null) + { + m_physicsScene.BeforeStep -= Hoverer; + m_hoverMotor = null; + } + } + + // Called just before the simulation step. Update the vertical position for hoverness. + private void Hoverer(float timeStep) + { + // Don't do hovering while the object is selected. + if (!isActive) + return; + m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z); - m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. - - m_physicsScene.BeforeStep += Hoverer; + m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); + float targetHeight = m_hoverMotor.Step(timeStep); + + // 'targetHeight' is where we'd like the Z of the prim to be at this moment. + // Compute the amount of force to push us there. + float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass; + // Undo anything the object thinks it's doing at the moment + moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass; + + m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce)); + m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", + m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass); } - } - private void DeactivateHover() - { - if (m_hoverMotor != null) + // Based on current position, determine what we should be hovering at now. + // Must recompute often. What if we walked offa cliff> + private float ComputeCurrentHoverHeight() { - m_physicsScene.BeforeStep -= Hoverer; - m_hoverMotor = null; - } - } - - // Called just before the simulation step. Update the vertical position for hoverness. - private void Hoverer(float timeStep) - { - // Don't do hovering while the object is selected. - if (!isActive) - return; - - m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z); - m_hoverMotor.SetTarget(ComputeCurrentHoverHeight()); - float targetHeight = m_hoverMotor.Step(timeStep); - - // 'targetHeight' is where we'd like the Z of the prim to be at this moment. - // Compute the amount of force to push us there. - float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass; - // Undo anything the object thinks it's doing at the moment - moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass; - - m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce)); - m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", - m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass); - } - - // Based on current position, determine what we should be hovering at now. - // Must recompute often. What if we walked offa cliff> - private float ComputeCurrentHoverHeight() - { - float ret = m_controllingPrim.HoverHeight; - float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition); - - switch (m_controllingPrim.HoverType) - { - case PIDHoverType.Ground: - ret = groundHeight + m_controllingPrim.HoverHeight; - break; - case PIDHoverType.GroundAndWater: - float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition); - if (groundHeight > waterHeight) - { + float ret = m_controllingPrim.HoverHeight; + float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition); + + switch (m_controllingPrim.HoverType) + { + case PIDHoverType.Ground: ret = groundHeight + m_controllingPrim.HoverHeight; - } - else - { - ret = waterHeight + m_controllingPrim.HoverHeight; - } - break; + break; + case PIDHoverType.GroundAndWater: + float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition); + if (groundHeight > waterHeight) + { + ret = groundHeight + m_controllingPrim.HoverHeight; + } + else + { + ret = waterHeight + m_controllingPrim.HoverHeight; + } + break; + } + return ret; } - return ret; } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs index 78c1b6aacb..3a00d42f76 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorLockAxis.cs @@ -34,186 +34,186 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -public class BSActorLockAxis : BSActor -{ - private BSConstraint LockAxisConstraint = null; - private bool HaveRegisteredForBeforeStepCallback = false; - - // The lock access flags (which axises were locked) when the contraint was built. - // Used to see if locking has changed since when the constraint was built. - OMV.Vector3 LockAxisLinearFlags; - OMV.Vector3 LockAxisAngularFlags; - - public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) - : base(physicsScene, pObj, actorName) + public class BSActorLockAxis : BSActor { - m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID); - LockAxisConstraint = null; - HaveRegisteredForBeforeStepCallback = false; - } + private BSConstraint LockAxisConstraint = null; + private bool HaveRegisteredForBeforeStepCallback = false; - // BSActor.isActive - public override bool isActive - { - get { return Enabled && m_controllingPrim.IsPhysicallyActive; } - } + // The lock access flags (which axises were locked) when the contraint was built. + // Used to see if locking has changed since when the constraint was built. + OMV.Vector3 LockAxisLinearFlags; + OMV.Vector3 LockAxisAngularFlags; - // Release any connections and resources used by the actor. - // BSActor.Dispose() - public override void Dispose() - { - Enabled = false; - UnRegisterForBeforeStepCallback(); - RemoveAxisLockConstraint(); - } - - // Called when physical parameters (properties set in Bullet) need to be re-applied. - // Called at taint-time. - // BSActor.Refresh() - public override void Refresh() - { - // Since the axis logging is done with a constraint, Refresh() time is good for - // changing parameters but this needs to wait until the prim/linkset is physically - // constructed. Therefore, the constraint itself is placed at pre-step time. - - // If all the axis are free, we don't need to exist - // Refresh() only turns off. Enabling is done by InitializeAxisActor() - // whenever parameters are changed. - // This leaves 'enable' free to turn off an actor when it is not wanted to run. - if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree - && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree) + public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) { - Enabled = false; - } - - if (isActive) - { - RegisterForBeforeStepCallback(); - } - else - { - RemoveDependencies(); - UnRegisterForBeforeStepCallback(); - } - } - - // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). - // Register a prestep action to restore physical requirements before the next simulation step. - // Called at taint-time. - // BSActor.RemoveDependencies() - public override void RemoveDependencies() - { - RemoveAxisLockConstraint(); - } - - private void RegisterForBeforeStepCallback() - { - if (!HaveRegisteredForBeforeStepCallback) - { - m_physicsScene.BeforeStep += PhysicsScene_BeforeStep; - HaveRegisteredForBeforeStepCallback = true; - } - } - - private void UnRegisterForBeforeStepCallback() - { - if (HaveRegisteredForBeforeStepCallback) - { - m_physicsScene.BeforeStep -= PhysicsScene_BeforeStep; + m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID); + LockAxisConstraint = null; HaveRegisteredForBeforeStepCallback = false; } - } - private void PhysicsScene_BeforeStep(float timestep) - { - // If all the axis are free, we don't need to exist - if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree - && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree) + // BSActor.isActive + public override bool isActive + { + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() { Enabled = false; + UnRegisterForBeforeStepCallback(); + RemoveAxisLockConstraint(); } - // If the object is physically active, add the axis locking constraint - if (isActive) + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() { - // Check to see if the locking parameters have changed - if (m_controllingPrim.LockedLinearAxis != this.LockAxisLinearFlags - || m_controllingPrim.LockedAngularAxis != this.LockAxisAngularFlags) + // Since the axis logging is done with a constraint, Refresh() time is good for + // changing parameters but this needs to wait until the prim/linkset is physically + // constructed. Therefore, the constraint itself is placed at pre-step time. + + // If all the axis are free, we don't need to exist + // Refresh() only turns off. Enabling is done by InitializeAxisActor() + // whenever parameters are changed. + // This leaves 'enable' free to turn off an actor when it is not wanted to run. + if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree + && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree) + { + Enabled = false; + } + + if (isActive) + { + RegisterForBeforeStepCallback(); + } + else + { + RemoveDependencies(); + UnRegisterForBeforeStepCallback(); + } + } + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveDependencies() + public override void RemoveDependencies() + { + RemoveAxisLockConstraint(); + } + + private void RegisterForBeforeStepCallback() + { + if (!HaveRegisteredForBeforeStepCallback) + { + m_physicsScene.BeforeStep += PhysicsScene_BeforeStep; + HaveRegisteredForBeforeStepCallback = true; + } + } + + private void UnRegisterForBeforeStepCallback() + { + if (HaveRegisteredForBeforeStepCallback) + { + m_physicsScene.BeforeStep -= PhysicsScene_BeforeStep; + HaveRegisteredForBeforeStepCallback = false; + } + } + + private void PhysicsScene_BeforeStep(float timestep) + { + // If all the axis are free, we don't need to exist + if (m_controllingPrim.LockedAngularAxis == m_controllingPrim.LockedAxisFree + && m_controllingPrim.LockedLinearAxis == m_controllingPrim.LockedAxisFree) + { + Enabled = false; + } + + // If the object is physically active, add the axis locking constraint + if (isActive) + { + // Check to see if the locking parameters have changed + if (m_controllingPrim.LockedLinearAxis != this.LockAxisLinearFlags + || m_controllingPrim.LockedAngularAxis != this.LockAxisAngularFlags) + { + // The locking has changed. Remove the old constraint and build a new one + RemoveAxisLockConstraint(); + } + + AddAxisLockConstraint(); + } + else { - // The locking has changed. Remove the old constraint and build a new one RemoveAxisLockConstraint(); } - - AddAxisLockConstraint(); } - else + + // Note that this relies on being called at TaintTime + private void AddAxisLockConstraint() { - RemoveAxisLockConstraint(); - } - } - - // Note that this relies on being called at TaintTime - private void AddAxisLockConstraint() - { - if (LockAxisConstraint == null) - { - // Lock that axis by creating a 6DOF constraint that has one end in the world and - // the other in the object. - // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 - // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 - - // Remove any existing axis constraint (just to be sure) - RemoveAxisLockConstraint(); - - BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody, - OMV.Vector3.Zero, OMV.Quaternion.Identity, - false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */); - LockAxisConstraint = axisConstrainer; - m_physicsScene.Constraints.AddConstraint(LockAxisConstraint); - - // Remember the clocking being inforced so we can notice if they have changed - LockAxisLinearFlags = m_controllingPrim.LockedLinearAxis; - LockAxisAngularFlags = m_controllingPrim.LockedAngularAxis; - - // The constraint is tied to the world and oriented to the prim. - - if (!axisConstrainer.SetLinearLimits(m_controllingPrim.LockedLinearAxisLow, m_controllingPrim.LockedLinearAxisHigh)) + if (LockAxisConstraint == null) { - m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetLinearLimits", - m_controllingPrim.LocalID); + // Lock that axis by creating a 6DOF constraint that has one end in the world and + // the other in the object. + // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817 + // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380 + + // Remove any existing axis constraint (just to be sure) + RemoveAxisLockConstraint(); + + BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody, + OMV.Vector3.Zero, OMV.Quaternion.Identity, + false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */); + LockAxisConstraint = axisConstrainer; + m_physicsScene.Constraints.AddConstraint(LockAxisConstraint); + + // Remember the clocking being inforced so we can notice if they have changed + LockAxisLinearFlags = m_controllingPrim.LockedLinearAxis; + LockAxisAngularFlags = m_controllingPrim.LockedAngularAxis; + + // The constraint is tied to the world and oriented to the prim. + + if (!axisConstrainer.SetLinearLimits(m_controllingPrim.LockedLinearAxisLow, m_controllingPrim.LockedLinearAxisHigh)) + { + m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetLinearLimits", + m_controllingPrim.LocalID); + } + + if (!axisConstrainer.SetAngularLimits(m_controllingPrim.LockedAngularAxisLow, m_controllingPrim.LockedAngularAxisHigh)) + { + m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", + m_controllingPrim.LocalID); + } + + m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", + m_controllingPrim.LocalID, + m_controllingPrim.LockedLinearAxisLow, + m_controllingPrim.LockedLinearAxisHigh, + m_controllingPrim.LockedAngularAxisLow, + m_controllingPrim.LockedAngularAxisHigh); + + // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. + axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); + + axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass); + + RegisterForBeforeStepCallback(); } - - if (!axisConstrainer.SetAngularLimits(m_controllingPrim.LockedAngularAxisLow, m_controllingPrim.LockedAngularAxisHigh)) - { - m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", - m_controllingPrim.LocalID); - } - - m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", - m_controllingPrim.LocalID, - m_controllingPrim.LockedLinearAxisLow, - m_controllingPrim.LockedLinearAxisHigh, - m_controllingPrim.LockedAngularAxisLow, - m_controllingPrim.LockedAngularAxisHigh); - - // Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. - axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); - - axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass); - - RegisterForBeforeStepCallback(); } - } - private void RemoveAxisLockConstraint() - { - UnRegisterForBeforeStepCallback(); - if (LockAxisConstraint != null) + private void RemoveAxisLockConstraint() { - m_physicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint); - LockAxisConstraint = null; - m_physicsScene.DetailLog("{0},BSActorLockAxis.RemoveAxisLockConstraint,destroyingConstraint", m_controllingPrim.LocalID); + UnRegisterForBeforeStepCallback(); + if (LockAxisConstraint != null) + { + m_physicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint); + LockAxisConstraint = null; + m_physicsScene.DetailLog("{0},BSActorLockAxis.RemoveAxisLockConstraint,destroyingConstraint", m_controllingPrim.LocalID); + } } } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs index f2019aeafe..eaf9571b2c 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorMoveToTarget.cs @@ -36,185 +36,185 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -public class BSActorMoveToTarget : BSActor -{ - private BSVMotor m_targetMotor; - - public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName) - : base(physicsScene, pObj, actorName) + public class BSActorMoveToTarget : BSActor { - m_targetMotor = null; - m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID); - } + private BSVMotor m_targetMotor; - // BSActor.isActive - public override bool isActive - { - // MoveToTarget only works on physical prims - get { return Enabled && m_controllingPrim.IsPhysicallyActive; } - } + public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_targetMotor = null; + m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID); + } - // Release any connections and resources used by the actor. - // BSActor.Dispose() - public override void Dispose() - { - Enabled = false; - DeactivateMoveToTarget(); - } + // BSActor.isActive + public override bool isActive + { + // MoveToTarget only works on physical prims + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } - // Called when physical parameters (properties set in Bullet) need to be re-applied. - // Called at taint-time. - // BSActor.Refresh() - public override void Refresh() - { - m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}", - m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive, - m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau ); - - // If not active any more... - if (!m_controllingPrim.MoveToTargetActive) + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() { Enabled = false; - } - - if (isActive) - { - ActivateMoveToTarget(); - } - else - { DeactivateMoveToTarget(); } - } - // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). - // Register a prestep action to restore physical requirements before the next simulation step. - // Called at taint-time. - // BSActor.RemoveDependencies() - public override void RemoveDependencies() - { - // Nothing to do for the moveToTarget since it is all software at pre-step action time. - } - - // If a hover motor has not been created, create one and start the hovering. - private void ActivateMoveToTarget() - { - if (m_targetMotor == null) + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() { - // We're taking over after this. - m_controllingPrim.ZeroMotion(true); + m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,enabled={1},active={2},target={3},tau={4}", + m_controllingPrim.LocalID, Enabled, m_controllingPrim.MoveToTargetActive, + m_controllingPrim.MoveToTargetTarget, m_controllingPrim.MoveToTargetTau ); - /* Someday use the PID controller - m_targetMotor = new BSPIDVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString()); - m_targetMotor.TimeScale = m_controllingPrim.MoveToTargetTau; - m_targetMotor.Efficiency = 1f; - */ - m_targetMotor = new BSVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString(), - m_controllingPrim.MoveToTargetTau, // timeScale - BSMotor.Infinite, // decay time scale - 1f // efficiency - ); - m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. - m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); - m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); + // If not active any more... + if (!m_controllingPrim.MoveToTargetActive) + { + Enabled = false; + } - // m_physicsScene.BeforeStep += Mover; - m_physicsScene.BeforeStep += Mover2; + if (isActive) + { + ActivateMoveToTarget(); + } + else + { + DeactivateMoveToTarget(); + } } - else + + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveDependencies() + public override void RemoveDependencies() { - // If already allocated, make sure the target and other paramters are current - m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); - m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); + // Nothing to do for the moveToTarget since it is all software at pre-step action time. } - } - private void DeactivateMoveToTarget() - { - if (m_targetMotor != null) + // If a hover motor has not been created, create one and start the hovering. + private void ActivateMoveToTarget() { - // m_physicsScene.BeforeStep -= Mover; - m_physicsScene.BeforeStep -= Mover2; - m_targetMotor = null; + if (m_targetMotor == null) + { + // We're taking over after this. + m_controllingPrim.ZeroMotion(true); + + /* Someday use the PID controller + m_targetMotor = new BSPIDVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString()); + m_targetMotor.TimeScale = m_controllingPrim.MoveToTargetTau; + m_targetMotor.Efficiency = 1f; + */ + m_targetMotor = new BSVMotor("BSActorMoveToTarget-" + m_controllingPrim.LocalID.ToString(), + m_controllingPrim.MoveToTargetTau, // timeScale + BSMotor.Infinite, // decay time scale + 1f // efficiency + ); + m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages. + m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); + m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); + + // m_physicsScene.BeforeStep += Mover; + m_physicsScene.BeforeStep += Mover2; + } + else + { + // If already allocated, make sure the target and other paramters are current + m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget); + m_targetMotor.SetCurrent(m_controllingPrim.RawPosition); + } } - } - // Origional mover that set the objects position to move to the target. - // The problem was that gravity would keep trying to push the object down so - // the overall downward velocity would increase to infinity. - // Called just before the simulation step. - private void Mover(float timeStep) - { - // Don't do hovering while the object is selected. - if (!isActive) - return; - - OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) - - // 'movePosition' is where we'd like the prim to be at this moment. - OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep); - - // If we are very close to our target, turn off the movement motor. - if (m_targetMotor.ErrorIsZero()) + private void DeactivateMoveToTarget() { - m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}", - m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass); - m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; - m_controllingPrim.ForceVelocity = OMV.Vector3.Zero; - // Setting the position does not cause the physics engine to generate a property update. Force it. - m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); + if (m_targetMotor != null) + { + // m_physicsScene.BeforeStep -= Mover; + m_physicsScene.BeforeStep -= Mover2; + m_targetMotor = null; + } } - else + + // Origional mover that set the objects position to move to the target. + // The problem was that gravity would keep trying to push the object down so + // the overall downward velocity would increase to infinity. + // Called just before the simulation step. + private void Mover(float timeStep) { - m_controllingPrim.ForcePosition = movePosition; - // Setting the position does not cause the physics engine to generate a property update. Force it. - m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); + // Don't do hovering while the object is selected. + if (!isActive) + return; + + OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) + + // 'movePosition' is where we'd like the prim to be at this moment. + OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep); + + // If we are very close to our target, turn off the movement motor. + if (m_targetMotor.ErrorIsZero()) + { + m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,zeroMovement,movePos={1},pos={2},mass={3}", + m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass); + m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; + m_controllingPrim.ForceVelocity = OMV.Vector3.Zero; + // Setting the position does not cause the physics engine to generate a property update. Force it. + m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); + } + else + { + m_controllingPrim.ForcePosition = movePosition; + // Setting the position does not cause the physics engine to generate a property update. Force it. + m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); + } + m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", + m_controllingPrim.LocalID, origPosition, movePosition); } - m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover,move,fromPos={1},movePos={2}", - m_controllingPrim.LocalID, origPosition, movePosition); - } - // Version of mover that applies forces to move the physical object to the target. - // Also overcomes gravity so the object doesn't just drop to the ground. - // Called just before the simulation step. - private void Mover2(float timeStep) - { - // Don't do hovering while the object is selected. - if (!isActive) - return; - - OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) - OMV.Vector3 addedForce = OMV.Vector3.Zero; - - // CorrectionVector is the movement vector required this step - OMV.Vector3 correctionVector = m_targetMotor.Step(timeStep, m_controllingPrim.RawPosition); - - // If we are very close to our target, turn off the movement motor. - if (m_targetMotor.ErrorIsZero()) + // Version of mover that applies forces to move the physical object to the target. + // Also overcomes gravity so the object doesn't just drop to the ground. + // Called just before the simulation step. + private void Mover2(float timeStep) { - m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,zeroMovement,pos={1},mass={2}", - m_controllingPrim.LocalID, m_controllingPrim.RawPosition, m_controllingPrim.Mass); - m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; - m_controllingPrim.ForceVelocity = OMV.Vector3.Zero; - // Setting the position does not cause the physics engine to generate a property update. Force it. - m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); - } - else - { - // First force to move us there -- the motor return a timestep scaled value. - addedForce = correctionVector / timeStep; - // Remove the existing velocity (only the moveToTarget force counts) - addedForce -= m_controllingPrim.RawVelocity; - // Overcome gravity. - addedForce -= m_controllingPrim.Gravity; + // Don't do hovering while the object is selected. + if (!isActive) + return; - // Add enough force to overcome the mass of the object - addedForce *= m_controllingPrim.Mass; + OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below) + OMV.Vector3 addedForce = OMV.Vector3.Zero; - m_controllingPrim.AddForce(true /* inTaintTime */, addedForce); + // CorrectionVector is the movement vector required this step + OMV.Vector3 correctionVector = m_targetMotor.Step(timeStep, m_controllingPrim.RawPosition); + + // If we are very close to our target, turn off the movement motor. + if (m_targetMotor.ErrorIsZero()) + { + m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,zeroMovement,pos={1},mass={2}", + m_controllingPrim.LocalID, m_controllingPrim.RawPosition, m_controllingPrim.Mass); + m_controllingPrim.ForcePosition = m_targetMotor.TargetValue; + m_controllingPrim.ForceVelocity = OMV.Vector3.Zero; + // Setting the position does not cause the physics engine to generate a property update. Force it. + m_physicsScene.PE.PushUpdate(m_controllingPrim.PhysBody); + } + else + { + // First force to move us there -- the motor return a timestep scaled value. + addedForce = correctionVector / timeStep; + // Remove the existing velocity (only the moveToTarget force counts) + addedForce -= m_controllingPrim.RawVelocity; + // Overcome gravity. + addedForce -= m_controllingPrim.Gravity; + + // Add enough force to overcome the mass of the object + addedForce *= m_controllingPrim.Mass; + + m_controllingPrim.AddForce(true /* inTaintTime */, addedForce); + } + m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,move,fromPos={1},addedForce={2}", + m_controllingPrim.LocalID, origPosition, addedForce); } - m_physicsScene.DetailLog("{0},BSActorMoveToTarget.Mover3,move,fromPos={1},addedForce={2}", - m_controllingPrim.LocalID, origPosition, addedForce); } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs index ecb4b7ff55..563b3862bc 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetForce.cs @@ -36,103 +36,103 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -public class BSActorSetForce : BSActor -{ - BSFMotor m_forceMotor; - - public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName) - : base(physicsScene, pObj, actorName) + public class BSActorSetForce : BSActor { - m_forceMotor = null; - m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID); - } + BSFMotor m_forceMotor; - // BSActor.isActive - public override bool isActive - { - get { return Enabled && m_controllingPrim.IsPhysicallyActive; } - } - - // Release any connections and resources used by the actor. - // BSActor.Dispose() - public override void Dispose() - { - Enabled = false; - DeactivateSetForce(); - } - - // Called when physical parameters (properties set in Bullet) need to be re-applied. - // Called at taint-time. - // BSActor.Refresh() - public override void Refresh() - { - m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID); - - // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) - if (m_controllingPrim.RawForce == OMV.Vector3.Zero) + public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_forceMotor = null; + m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID); + } + + // BSActor.isActive + public override bool isActive + { + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() { - m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName); Enabled = false; - return; - } - - // If the object is physically active, add the hoverer prestep action - if (isActive) - { - ActivateSetForce(); - } - else - { DeactivateSetForce(); } - } - // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). - // Register a prestep action to restore physical requirements before the next simulation step. - // Called at taint-time. - // BSActor.RemoveDependencies() - public override void RemoveDependencies() - { - // Nothing to do for the hoverer since it is all software at pre-step action time. - } - - // If a hover motor has not been created, create one and start the hovering. - private void ActivateSetForce() - { - if (m_forceMotor == null) + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() { - // A fake motor that might be used someday - m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f); + m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID); - m_physicsScene.BeforeStep += Mover; - } - } + // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) + if (m_controllingPrim.RawForce == OMV.Vector3.Zero) + { + m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName); + Enabled = false; + return; + } - private void DeactivateSetForce() - { - if (m_forceMotor != null) - { - m_physicsScene.BeforeStep -= Mover; - m_forceMotor = null; - } - } - - // Called just before the simulation step. Update the vertical position for hoverness. - private void Mover(float timeStep) - { - // Don't do force while the object is selected. - if (!isActive) - return; - - m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce); - if (m_controllingPrim.PhysBody.HasPhysicalBody) - { - m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce); - m_controllingPrim.ActivateIfPhysical(false); + // If the object is physically active, add the hoverer prestep action + if (isActive) + { + ActivateSetForce(); + } + else + { + DeactivateSetForce(); + } } - // TODO: + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveDependencies() + public override void RemoveDependencies() + { + // Nothing to do for the hoverer since it is all software at pre-step action time. + } + + // If a hover motor has not been created, create one and start the hovering. + private void ActivateSetForce() + { + if (m_forceMotor == null) + { + // A fake motor that might be used someday + m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f); + + m_physicsScene.BeforeStep += Mover; + } + } + + private void DeactivateSetForce() + { + if (m_forceMotor != null) + { + m_physicsScene.BeforeStep -= Mover; + m_forceMotor = null; + } + } + + // Called just before the simulation step. Update the vertical position for hoverness. + private void Mover(float timeStep) + { + // Don't do force while the object is selected. + if (!isActive) + return; + + m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce); + if (m_controllingPrim.PhysBody.HasPhysicalBody) + { + m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce); + m_controllingPrim.ActivateIfPhysical(false); + } + + // TODO: + } } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs index 0261bcb937..c18cabf4a4 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActorSetTorque.cs @@ -36,104 +36,102 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -public class BSActorSetTorque : BSActor -{ - BSFMotor m_torqueMotor; - - public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName) - : base(physicsScene, pObj, actorName) + public class BSActorSetTorque : BSActor { - m_torqueMotor = null; - m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID); - } + BSFMotor m_torqueMotor; - // BSActor.isActive - public override bool isActive - { - get { return Enabled && m_controllingPrim.IsPhysicallyActive; } - } - - // Release any connections and resources used by the actor. - // BSActor.Dispose() - public override void Dispose() - { - Enabled = false; - DeactivateSetTorque(); - } - - // Called when physical parameters (properties set in Bullet) need to be re-applied. - // Called at taint-time. - // BSActor.Refresh() - public override void Refresh() - { - m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); - - // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) - if (m_controllingPrim.RawTorque == OMV.Vector3.Zero) + public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName) + : base(physicsScene, pObj, actorName) + { + m_torqueMotor = null; + m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID); + } + + // BSActor.isActive + public override bool isActive + { + get { return Enabled && m_controllingPrim.IsPhysicallyActive; } + } + + // Release any connections and resources used by the actor. + // BSActor.Dispose() + public override void Dispose() { - m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName); Enabled = false; - return; - } - - // If the object is physically active, add the hoverer prestep action - if (isActive) - { - ActivateSetTorque(); - } - else - { DeactivateSetTorque(); } - } - // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). - // Register a prestep action to restore physical requirements before the next simulation step. - // Called at taint-time. - // BSActor.RemoveDependencies() - public override void RemoveDependencies() - { - // Nothing to do for the hoverer since it is all software at pre-step action time. - } - - // If a hover motor has not been created, create one and start the hovering. - private void ActivateSetTorque() - { - if (m_torqueMotor == null) + // Called when physical parameters (properties set in Bullet) need to be re-applied. + // Called at taint-time. + // BSActor.Refresh() + public override void Refresh() { - // A fake motor that might be used someday - m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f); + m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); - m_physicsScene.BeforeStep += Mover; - } - } + // If not active any more, get rid of me (shouldn't ever happen, but just to be safe) + if (m_controllingPrim.RawTorque == OMV.Vector3.Zero) + { + m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,disabling={1}", m_controllingPrim.LocalID, ActorName); + Enabled = false; + return; + } - private void DeactivateSetTorque() - { - if (m_torqueMotor != null) - { - m_physicsScene.BeforeStep -= Mover; - m_torqueMotor = null; - } - } - - // Called just before the simulation step. Update the vertical position for hoverness. - private void Mover(float timeStep) - { - // Don't do force while the object is selected. - if (!isActive) - return; - - m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); - if (m_controllingPrim.PhysBody.HasPhysicalBody) - { - m_controllingPrim.AddAngularForce(true /* inTaintTime */, m_controllingPrim.RawTorque); - m_controllingPrim.ActivateIfPhysical(false); + // If the object is physically active, add the hoverer prestep action + if (isActive) + { + ActivateSetTorque(); + } + else + { + DeactivateSetTorque(); + } } - // TODO: + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + // Called at taint-time. + // BSActor.RemoveDependencies() + public override void RemoveDependencies() + { + // Nothing to do for the hoverer since it is all software at pre-step action time. + } + + // If a hover motor has not been created, create one and start the hovering. + private void ActivateSetTorque() + { + if (m_torqueMotor == null) + { + // A fake motor that might be used someday + m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f); + + m_physicsScene.BeforeStep += Mover; + } + } + + private void DeactivateSetTorque() + { + if (m_torqueMotor != null) + { + m_physicsScene.BeforeStep -= Mover; + m_torqueMotor = null; + } + } + + // Called just before the simulation step. Update the vertical position for hoverness. + private void Mover(float timeStep) + { + // Don't do force while the object is selected. + if (!isActive) + return; + + m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque); + if (m_controllingPrim.PhysBody.HasPhysicalBody) + { + m_controllingPrim.AddAngularForce(true /* inTaintTime */, m_controllingPrim.RawTorque); + m_controllingPrim.ActivateIfPhysical(false); + } + + // TODO: + } } } -} - - diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs index 851347b493..ba5ea0974c 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSActors.cs @@ -30,125 +30,125 @@ using System.Text; namespace OpenSim.Region.PhysicsModule.BulletS { -public class BSActorCollection -{ - private Dictionary m_actors; + public class BSActorCollection + { + private Dictionary m_actors; - public BSActorCollection() - { - m_actors = new Dictionary(); - } - public void Add(string name, BSActor actor) - { - lock (m_actors) + public BSActorCollection() { - if (!m_actors.ContainsKey(name)) + m_actors = new Dictionary(); + } + public void Add(string name, BSActor actor) + { + lock (m_actors) { - m_actors[name] = actor; + if (!m_actors.ContainsKey(name)) + { + m_actors[name] = actor; + } } } - } - public bool RemoveAndRelease(string name) - { - bool ret = false; - lock (m_actors) + public bool RemoveAndRelease(string name) { - if (m_actors.ContainsKey(name)) + bool ret = false; + lock (m_actors) { - BSActor beingRemoved = m_actors[name]; - m_actors.Remove(name); - beingRemoved.Dispose(); - ret = true; + if (m_actors.ContainsKey(name)) + { + BSActor beingRemoved = m_actors[name]; + m_actors.Remove(name); + beingRemoved.Dispose(); + ret = true; + } + } + return ret; + } + public void Clear() + { + lock (m_actors) + { + ForEachActor(a => a.Dispose()); + m_actors.Clear(); } } - return ret; - } - public void Clear() - { - lock (m_actors) + public void Dispose() { - ForEachActor(a => a.Dispose()); - m_actors.Clear(); + Clear(); } - } - public void Dispose() - { - Clear(); - } - public bool HasActor(string name) - { - return m_actors.ContainsKey(name); - } - public bool TryGetActor(string actorName, out BSActor theActor) - { - return m_actors.TryGetValue(actorName, out theActor); - } - public void ForEachActor(Action act) - { - lock (m_actors) + public bool HasActor(string name) { - foreach (KeyValuePair kvp in m_actors) - act(kvp.Value); + return m_actors.ContainsKey(name); + } + public bool TryGetActor(string actorName, out BSActor theActor) + { + return m_actors.TryGetValue(actorName, out theActor); + } + public void ForEachActor(Action act) + { + lock (m_actors) + { + foreach (KeyValuePair kvp in m_actors) + act(kvp.Value); + } + } + + public void Enable(bool enabl) + { + ForEachActor(a => a.SetEnabled(enabl)); + } + public void Refresh() + { + ForEachActor(a => a.Refresh()); + } + public void RemoveDependencies() + { + ForEachActor(a => a.RemoveDependencies()); } } - public void Enable(bool enabl) + // ============================================================================= + /// + /// Each physical object can have 'actors' who are pushing the object around. + /// This can be used for hover, locking axis, making vehicles, etc. + /// Each physical object can have multiple actors acting on it. + /// + /// An actor usually registers itself with physics scene events (pre-step action) + /// and modifies the parameters on the host physical object. + /// + public abstract class BSActor { - ForEachActor(a => a.SetEnabled(enabl)); - } - public void Refresh() - { - ForEachActor(a => a.Refresh()); - } - public void RemoveDependencies() - { - ForEachActor(a => a.RemoveDependencies()); + protected BSScene m_physicsScene { get; private set; } + protected BSPhysObject m_controllingPrim { get; private set; } + public virtual bool Enabled { get; set; } + public string ActorName { get; private set; } + + public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName) + { + m_physicsScene = physicsScene; + m_controllingPrim = pObj; + ActorName = actorName; + Enabled = true; + } + + // Return 'true' if activily updating the prim + public virtual bool isActive + { + get { return Enabled; } + } + + // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled. + // Anyone else should assign true/false to 'Enabled'. + public void SetEnabled(bool setEnabled) + { + Enabled = setEnabled; + } + // Release any connections and resources used by the actor. + public abstract void Dispose(); + // Called when physical parameters (properties set in Bullet) need to be re-applied. + public abstract void Refresh(); + // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). + // Register a prestep action to restore physical requirements before the next simulation step. + public abstract void RemoveDependencies(); + } } - -// ============================================================================= -/// -/// Each physical object can have 'actors' who are pushing the object around. -/// This can be used for hover, locking axis, making vehicles, etc. -/// Each physical object can have multiple actors acting on it. -/// -/// An actor usually registers itself with physics scene events (pre-step action) -/// and modifies the parameters on the host physical object. -/// -public abstract class BSActor -{ - protected BSScene m_physicsScene { get; private set; } - protected BSPhysObject m_controllingPrim { get; private set; } - public virtual bool Enabled { get; set; } - public string ActorName { get; private set; } - - public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName) - { - m_physicsScene = physicsScene; - m_controllingPrim = pObj; - ActorName = actorName; - Enabled = true; - } - - // Return 'true' if activily updating the prim - public virtual bool isActive - { - get { return Enabled; } - } - - // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled. - // Anyone else should assign true/false to 'Enabled'. - public void SetEnabled(bool setEnabled) - { - Enabled = setEnabled; - } - // Release any connections and resources used by the actor. - public abstract void Dispose(); - // Called when physical parameters (properties set in Bullet) need to be re-applied. - public abstract void Refresh(); - // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...). - // Register a prestep action to restore physical requirements before the next simulation step. - public abstract void RemoveDependencies(); - -} -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs index a2880487c2..6b84e0e6d7 100644 --- a/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSApiTemplate.cs @@ -31,754 +31,753 @@ using System.Security; using System.Text; using OpenMetaverse; -namespace OpenSim.Region.PhysicsModule.BulletS { - +namespace OpenSim.Region.PhysicsModule.BulletS +{ // Constraint type values as defined by Bullet -public enum ConstraintType : int -{ - POINT2POINT_CONSTRAINT_TYPE = 3, - HINGE_CONSTRAINT_TYPE, - CONETWIST_CONSTRAINT_TYPE, - D6_CONSTRAINT_TYPE, - SLIDER_CONSTRAINT_TYPE, - CONTACT_CONSTRAINT_TYPE, - D6_SPRING_CONSTRAINT_TYPE, - GEAR_CONSTRAINT_TYPE, // added in Bullet 2.82 - FIXED_CONSTRAINT_TYPE, // added in Bullet 2.82 - MAX_CONSTRAINT_TYPE, // last type defined by Bullet - // - BS_FIXED_CONSTRAINT_TYPE = 1234 // BulletSim constraint that is fixed and unmoving -} - -// =============================================================================== -[StructLayout(LayoutKind.Sequential)] -public struct ConvexHull -{ - Vector3 Offset; - int VertexCount; - Vector3[] Vertices; -} -public enum BSPhysicsShapeType -{ - SHAPE_UNKNOWN = 0, - SHAPE_CAPSULE = 1, - SHAPE_BOX = 2, - SHAPE_CONE = 3, - SHAPE_CYLINDER = 4, - SHAPE_SPHERE = 5, - SHAPE_MESH = 6, - SHAPE_HULL = 7, - // following defined by BulletSim - SHAPE_GROUNDPLANE = 20, - SHAPE_TERRAIN = 21, - SHAPE_COMPOUND = 22, - SHAPE_HEIGHTMAP = 23, - SHAPE_AVATAR = 24, - SHAPE_CONVEXHULL= 25, - SHAPE_GIMPACT = 26, -}; - -// The native shapes have predefined shape hash keys -public enum FixedShapeKey : ulong -{ - KEY_NONE = 0, - KEY_BOX = 1, - KEY_SPHERE = 2, - KEY_CONE = 3, - KEY_CYLINDER = 4, - KEY_CAPSULE = 5, - KEY_AVATAR = 6, -} - -[StructLayout(LayoutKind.Sequential)] -public struct ShapeData -{ - public UInt32 ID; - public BSPhysicsShapeType Type; - public Vector3 Position; - public Quaternion Rotation; - public Vector3 Velocity; - public Vector3 Scale; - public float Mass; - public float Buoyancy; - public System.UInt64 HullKey; - public System.UInt64 MeshKey; - public float Friction; - public float Restitution; - public float Collidable; // true of things bump into this - public float Static; // true if a static object. Otherwise gravity, etc. - public float Solid; // true if object cannot be passed through - public Vector3 Size; - - // note that bools are passed as floats since bool size changes by language and architecture - public const float numericTrue = 1f; - public const float numericFalse = 0f; -} -[StructLayout(LayoutKind.Sequential)] -public struct SweepHit -{ - public UInt32 ID; - public float Fraction; - public Vector3 Normal; - public Vector3 Point; - - public bool hasHit() + public enum ConstraintType : int { - float sum = Fraction - + Normal.X + Normal.Y + Normal.Z - + Point.X + Point.Y + Point.Z; - return (sum != 0) || (ID != 0); + POINT2POINT_CONSTRAINT_TYPE = 3, + HINGE_CONSTRAINT_TYPE, + CONETWIST_CONSTRAINT_TYPE, + D6_CONSTRAINT_TYPE, + SLIDER_CONSTRAINT_TYPE, + CONTACT_CONSTRAINT_TYPE, + D6_SPRING_CONSTRAINT_TYPE, + GEAR_CONSTRAINT_TYPE, // added in Bullet 2.82 + FIXED_CONSTRAINT_TYPE, // added in Bullet 2.82 + MAX_CONSTRAINT_TYPE, // last type defined by Bullet + // + BS_FIXED_CONSTRAINT_TYPE = 1234 // BulletSim constraint that is fixed and unmoving } -} -[StructLayout(LayoutKind.Sequential)] -public struct RaycastHit -{ - public UInt32 ID; - public float Fraction; - public Vector3 Normal; - public Vector3 Point; - public bool hasHit() + // =============================================================================== + [StructLayout(LayoutKind.Sequential)] + public struct ConvexHull { - float sum = Normal.X + Normal.Y + Normal.Z + Point.X + Point.Y + Point.Z; - return (sum != 0); + Vector3 Offset; + int VertexCount; + Vector3[] Vertices; } -} -[StructLayout(LayoutKind.Sequential)] -public struct CollisionDesc -{ - public UInt32 aID; - public UInt32 bID; - public Vector3 point; - public Vector3 normal; - public float penetration; -} -[StructLayout(LayoutKind.Sequential)] -public struct EntityProperties -{ - public UInt32 ID; - public Vector3 Position; - public Quaternion Rotation; - public Vector3 Velocity; - public Vector3 Acceleration; - public Vector3 RotationalVelocity; - - public override string ToString() + public enum BSPhysicsShapeType { - StringBuilder buff = new StringBuilder(); - buff.Append(""); - return buff.ToString(); + SHAPE_UNKNOWN = 0, + SHAPE_CAPSULE = 1, + SHAPE_BOX = 2, + SHAPE_CONE = 3, + SHAPE_CYLINDER = 4, + SHAPE_SPHERE = 5, + SHAPE_MESH = 6, + SHAPE_HULL = 7, + // following defined by BulletSim + SHAPE_GROUNDPLANE = 20, + SHAPE_TERRAIN = 21, + SHAPE_COMPOUND = 22, + SHAPE_HEIGHTMAP = 23, + SHAPE_AVATAR = 24, + SHAPE_CONVEXHULL= 25, + SHAPE_GIMPACT = 26, + }; + + // The native shapes have predefined shape hash keys + public enum FixedShapeKey : ulong + { + KEY_NONE = 0, + KEY_BOX = 1, + KEY_SPHERE = 2, + KEY_CONE = 3, + KEY_CYLINDER = 4, + KEY_CAPSULE = 5, + KEY_AVATAR = 6, } -} - -// Format of this structure must match the definition in the C++ code -// NOTE: adding the X causes compile breaks if used. These are unused symbols -// that can be removed from both here and the unmanaged definition of this structure. -[StructLayout(LayoutKind.Sequential)] -public struct ConfigurationParameters -{ - public float defaultFriction; - public float defaultDensity; - public float defaultRestitution; - public float collisionMargin; - public float gravity; - - public float maxPersistantManifoldPoolSize; - public float maxCollisionAlgorithmPoolSize; - public float shouldDisableContactPoolDynamicAllocation; - public float shouldForceUpdateAllAabbs; - public float shouldRandomizeSolverOrder; - public float shouldSplitSimulationIslands; - public float shouldEnableFrictionCaching; - public float numberOfSolverIterations; - public float useSingleSidedMeshes; - public float globalContactBreakingThreshold; - - public float physicsLoggingFrames; - - public const float numericTrue = 1f; - public const float numericFalse = 0f; -} - -// Parameters passed for the conversion of a mesh to a hull using Bullet's HACD library. -[StructLayout(LayoutKind.Sequential)] -public struct HACDParams -{ - // usual default values - public float maxVerticesPerHull; // 100 - public float minClusters; // 2 - public float compacityWeight; // 0.1 - public float volumeWeight; // 0.0 - public float concavity; // 100 - public float addExtraDistPoints; // false - public float addNeighboursDistPoints; // false - public float addFacesPoints; // false - public float shouldAdjustCollisionMargin; // false - // VHACD - public float whichHACD; // zero if Bullet HACD, non-zero says VHACD - // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html - public float vHACDresolution; // 100,000 max number of voxels generated during voxelization stage - public float vHACDdepth; // 20 max number of clipping stages - public float vHACDconcavity; // 0.0025 maximum concavity - public float vHACDplaneDownsampling; // 4 granularity of search for best clipping plane - public float vHACDconvexHullDownsampling; // 4 precision of hull gen process - public float vHACDalpha; // 0.05 bias toward clipping along symmetry planes - public float vHACDbeta; // 0.05 bias toward clipping along revolution axis - public float vHACDgamma; // 0.00125 max concavity when merging - public float vHACDpca; // 0 on/off normalizing mesh before decomp - public float vHACDmode; // 0 0:voxel based, 1: tetrahedron based - public float vHACDmaxNumVerticesPerCH; // 64 max triangles per convex hull - public float vHACDminVolumePerCH; // 0.0001 sampling of generated convex hulls -} - -// The states a bullet collision object can have -public enum ActivationState : uint -{ - ACTIVE_TAG = 1, - ISLAND_SLEEPING, - WANTS_DEACTIVATION, - DISABLE_DEACTIVATION, - DISABLE_SIMULATION, -} - -public enum CollisionObjectTypes : int -{ - CO_COLLISION_OBJECT = 1 << 0, - CO_RIGID_BODY = 1 << 1, - CO_GHOST_OBJECT = 1 << 2, - CO_SOFT_BODY = 1 << 3, - CO_HF_FLUID = 1 << 4, - CO_USER_TYPE = 1 << 5, -} - -// Values used by Bullet and BulletSim to control object properties. -// Bullet's "CollisionFlags" has more to do with operations on the -// object (if collisions happen, if gravity effects it, ...). -public enum CollisionFlags : uint -{ - CF_STATIC_OBJECT = 1 << 0, - CF_KINEMATIC_OBJECT = 1 << 1, - CF_NO_CONTACT_RESPONSE = 1 << 2, - CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3, - CF_CHARACTER_OBJECT = 1 << 4, - CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, - CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, - // Following used by BulletSim to control collisions and updates - BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed - BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level - BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking - BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape - BS_NONE = 0, - BS_ALL = 0x7FFF // collision flags are a signed short -}; - -// Values f collisions groups and masks -public enum CollisionFilterGroups : uint -{ - // Don't use the bit definitions!! Define the use in a - // filter/mask definition below. This way collision interactions - // are more easily found and debugged. - BNoneGroup = 0, - BDefaultGroup = 1 << 0, // 0001 - BStaticGroup = 1 << 1, // 0002 - BKinematicGroup = 1 << 2, // 0004 - BDebrisGroup = 1 << 3, // 0008 - BSensorTrigger = 1 << 4, // 0010 - BCharacterGroup = 1 << 5, // 0020 - BAllGroup = 0x0007FFF, // collision flags are a signed short - // Filter groups defined by BulletSim - BGroundPlaneGroup = 1 << 8, // 0400 - BTerrainGroup = 1 << 9, // 0800 - BRaycastGroup = 1 << 10, // 1000 - BSolidGroup = 1 << 11, // 2000 - // BLinksetGroup = xx // a linkset proper is either static or dynamic - BLinksetChildGroup = 1 << 12, // 4000 -}; - -// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 -// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. -public enum ConstraintParams : int -{ - BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730 - BT_CONSTRAINT_STOP_ERP, - BT_CONSTRAINT_CFM, - BT_CONSTRAINT_STOP_CFM, -}; -public enum ConstraintParamAxis : int -{ - AXIS_LINEAR_X = 0, - AXIS_LINEAR_Y, - AXIS_LINEAR_Z, - AXIS_ANGULAR_X, - AXIS_ANGULAR_Y, - AXIS_ANGULAR_Z, - AXIS_LINEAR_ALL = 20, // added by BulletSim so we don't have to do zillions of calls - AXIS_ANGULAR_ALL, - AXIS_ALL -}; - -public abstract class BSAPITemplate -{ -// Returns the name of the underlying Bullet engine -public abstract string BulletEngineName { get; } -public abstract string BulletEngineVersion { get; protected set;} - -// Initialization and simulation -public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, - int maxCollisions, ref CollisionDesc[] collisionArray, - int maxUpdates, ref EntityProperties[] updateArray - ); - -public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, - out int updatedEntityCount, out int collidersCount); - -public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value); - -public abstract void Shutdown(BulletWorld sim); - -public abstract bool PushUpdate(BulletBody obj); - -// ===================================================================================== -// Mesh, hull, shape and body creation helper routines -public abstract BulletShape CreateMeshShape(BulletWorld world, - int indicesCount, int[] indices, - int verticesCount, float[] vertices ); - -public abstract BulletShape CreateGImpactShape(BulletWorld world, - int indicesCount, int[] indices, - int verticesCount, float[] vertices ); - -public abstract BulletShape CreateHullShape(BulletWorld world, - int hullCount, float[] hulls); - -public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms); - -public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape); - -public abstract BulletShape CreateConvexHullShape(BulletWorld world, - int indicesCount, int[] indices, - int verticesCount, float[] vertices ); - -public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); - -public abstract bool IsNativeShape(BulletShape shape); - -public abstract void SetShapeCollisionMargin(BulletShape shape, float margin); - -public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale); - -public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree); - -public abstract int GetNumberOfCompoundChildren(BulletShape cShape); - -public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot); - -public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); - -public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); - -public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape); - -public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb); - -public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape); - -public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id); - -public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape); - -public abstract CollisionObjectTypes GetBodyType(BulletBody obj); - -public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); - -public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); - -public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); - -public abstract void DestroyObject(BulletWorld sim, BulletBody obj); - -// ===================================================================================== -public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); - -public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, - float scaleFactor, float collisionMargin); - -// ===================================================================================== -// Constraint creation and helper routines -public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frame1loc, Quaternion frame1rot, - Vector3 frame2loc, Quaternion frame2rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 joinPoint, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, - Vector3 frameInBloc, Quaternion frameInBrot, - bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); - -public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frame1loc, Quaternion frame1rot, - Vector3 frame2loc, Quaternion frame2rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 pivotinA, Vector3 pivotinB, - Vector3 axisInA, Vector3 axisInB, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -public abstract BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frameInAloc, Quaternion frameInArot, - Vector3 frameInBloc, Quaternion frameInBrot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); - -public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frameInAloc, Quaternion frameInArot, - Vector3 frameInBloc, Quaternion frameInBrot, - bool disableCollisionsBetweenLinkedBodies); - -public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 axisInA, Vector3 axisInB, - float ratio, bool disableCollisionsBetweenLinkedBodies); - -public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 pivotInA, Vector3 pivotInB, - bool disableCollisionsBetweenLinkedBodies); - -public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse); - -public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations); - -public abstract bool SetFrames(BulletConstraint constrain, - Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); - -public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); - -public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); - -public abstract bool UseFrameOffset(BulletConstraint constrain, float enable); - -public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce); - -public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold); - -public const int HINGE_NOT_SPECIFIED = -1; -public abstract bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation); - -public abstract bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse); - -public const int SPRING_NOT_SPECIFIED = -1; -public abstract bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint); - -public abstract bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss); - -public abstract bool SpringSetDamping(BulletConstraint constrain, int index, float damping); - -public const int SLIDER_LOWER_LIMIT = 0; -public const int SLIDER_UPPER_LIMIT = 1; -public const int SLIDER_LINEAR = 2; -public const int SLIDER_ANGULAR = 3; -public abstract bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val); - -public const int SLIDER_SET_SOFTNESS = 4; -public const int SLIDER_SET_RESTITUTION = 5; -public const int SLIDER_SET_DAMPING = 6; -public const int SLIDER_SET_DIRECTION = 7; -public const int SLIDER_SET_LIMIT = 8; -public const int SLIDER_SET_ORTHO = 9; -public abstract bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val); - -public abstract bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse); - -public const int SLIDER_MOTOR_VELOCITY = 10; -public const int SLIDER_MAX_MOTOR_FORCE = 11; -public abstract bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val); - -public abstract bool CalculateTransforms(BulletConstraint constrain); - -public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); - -public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain); - -// ===================================================================================== -// btCollisionWorld entries -public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj); - -public abstract void UpdateAabbs(BulletWorld world); - -public abstract bool GetForceUpdateAllAabbs(BulletWorld world); - -public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force); - -// ===================================================================================== -// btDynamicsWorld entries -// public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot); -public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj); - -public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj); - -public abstract bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj); - -public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects); - -public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain); -// ===================================================================================== -// btCollisionObject entries -public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain); - -public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict); - -public abstract bool HasAnisotripicFriction(BulletConstraint constrain); - -public abstract void SetContactProcessingThreshold(BulletBody obj, float val); - -public abstract float GetContactProcessingThreshold(BulletBody obj); - -public abstract bool IsStaticObject(BulletBody obj); - -public abstract bool IsKinematicObject(BulletBody obj); - -public abstract bool IsStaticOrKinematicObject(BulletBody obj); - -public abstract bool HasContactResponse(BulletBody obj); - -public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape); - -public abstract BulletShape GetCollisionShape(BulletBody obj); - -public abstract int GetActivationState(BulletBody obj); - -public abstract void SetActivationState(BulletBody obj, int state); - -public abstract void SetDeactivationTime(BulletBody obj, float dtime); - -public abstract float GetDeactivationTime(BulletBody obj); - -public abstract void ForceActivationState(BulletBody obj, ActivationState state); - -public abstract void Activate(BulletBody obj, bool forceActivation); - -public abstract bool IsActive(BulletBody obj); - -public abstract void SetRestitution(BulletBody obj, float val); - -public abstract float GetRestitution(BulletBody obj); - -public abstract void SetFriction(BulletBody obj, float val); - -public abstract float GetFriction(BulletBody obj); - -public abstract Vector3 GetPosition(BulletBody obj); - -public abstract Quaternion GetOrientation(BulletBody obj); - -public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation); - -// public abstract IntPtr GetBroadphaseHandle(BulletBody obj); - -// public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle); - -public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel); - -public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel); - -public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel); - -public abstract float GetHitFraction(BulletBody obj); - -public abstract void SetHitFraction(BulletBody obj, float val); - -public abstract CollisionFlags GetCollisionFlags(BulletBody obj); - -public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags); - -public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags); - -public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags); - -public abstract float GetCcdMotionThreshold(BulletBody obj); - -public abstract void SetCcdMotionThreshold(BulletBody obj, float val); - -public abstract float GetCcdSweptSphereRadius(BulletBody obj); - -public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val); - -public abstract IntPtr GetUserPointer(BulletBody obj); - -public abstract void SetUserPointer(BulletBody obj, IntPtr val); - -// ===================================================================================== -// btRigidBody entries -public abstract void ApplyGravity(BulletBody obj); - -public abstract void SetGravity(BulletBody obj, Vector3 val); - -public abstract Vector3 GetGravity(BulletBody obj); - -public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping); - -public abstract void SetLinearDamping(BulletBody obj, float lin_damping); - -public abstract void SetAngularDamping(BulletBody obj, float ang_damping); - -public abstract float GetLinearDamping(BulletBody obj); - -public abstract float GetAngularDamping(BulletBody obj); - -public abstract float GetLinearSleepingThreshold(BulletBody obj); - -public abstract void ApplyDamping(BulletBody obj, float timeStep); - -public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia); - -public abstract Vector3 GetLinearFactor(BulletBody obj); - -public abstract void SetLinearFactor(BulletBody obj, Vector3 factor); - -public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot); - -// Add a force to the object as if its mass is one. -public abstract void ApplyCentralForce(BulletBody obj, Vector3 force); - -// Set the force being applied to the object as if its mass is one. -public abstract void SetObjectForce(BulletBody obj, Vector3 force); - -public abstract Vector3 GetTotalForce(BulletBody obj); - -public abstract Vector3 GetTotalTorque(BulletBody obj); - -public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj); - -public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert); - -public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold); - -public abstract void ApplyTorque(BulletBody obj, Vector3 torque); - -// Apply force at the given point. Will add torque to the object. -public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos); - -// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. -public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp); - -// Apply impulse to the object's torque. Force is scaled by object's mass. -public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp); - -// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. -public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos); - -public abstract void ClearForces(BulletBody obj); - -public abstract void ClearAllForces(BulletBody obj); - -public abstract void UpdateInertiaTensor(BulletBody obj); - -public abstract Vector3 GetLinearVelocity(BulletBody obj); - -public abstract Vector3 GetAngularVelocity(BulletBody obj); - -public abstract void SetLinearVelocity(BulletBody obj, Vector3 val); - -public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity); - -public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos); - -public abstract void Translate(BulletBody obj, Vector3 trans); - -public abstract void UpdateDeactivation(BulletBody obj, float timeStep); - -public abstract bool WantsSleeping(BulletBody obj); - -public abstract void SetAngularFactor(BulletBody obj, float factor); - -public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor); - -public abstract Vector3 GetAngularFactor(BulletBody obj); - -public abstract bool IsInWorld(BulletWorld world, BulletBody obj); - -public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain); - -public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain); - -public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index); - -public abstract int GetNumConstraintRefs(BulletBody obj); - -public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask); - -// ===================================================================================== -// btCollisionShape entries - -public abstract float GetAngularMotionDisc(BulletShape shape); - -public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor); - -public abstract bool IsPolyhedral(BulletShape shape); - -public abstract bool IsConvex2d(BulletShape shape); - -public abstract bool IsConvex(BulletShape shape); - -public abstract bool IsNonMoving(BulletShape shape); - -public abstract bool IsConcave(BulletShape shape); - -public abstract bool IsCompound(BulletShape shape); - -public abstract bool IsSoftBody(BulletShape shape); - -public abstract bool IsInfinite(BulletShape shape); - -public abstract void SetLocalScaling(BulletShape shape, Vector3 scale); - -public abstract Vector3 GetLocalScaling(BulletShape shape); - -public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass); - -public abstract int GetShapeType(BulletShape shape); - -public abstract void SetMargin(BulletShape shape, float val); - -public abstract float GetMargin(BulletShape shape); - -// ===================================================================================== -// Raycast -public abstract SweepHit ConvexSweepTest2(BulletWorld world, BulletBody obj, Vector3 from, Vector3 to, float margin); - -public abstract RaycastHit RayTest2(BulletWorld world, Vector3 from, Vector3 to, uint filterGroup, uint filterMask); - -// ===================================================================================== -// Debugging -public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { } - -public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { } - -public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { } - -public virtual void DumpActivationInfo(BulletWorld sim) { } - -public virtual void DumpAllInfo(BulletWorld sim) { } - -public virtual void DumpPhysicsStatistics(BulletWorld sim) { } - -public virtual void ResetBroadphasePool(BulletWorld sim) { } - -public virtual void ResetConstraintSolver(BulletWorld sim) { } - -}; + + [StructLayout(LayoutKind.Sequential)] + public struct ShapeData + { + public UInt32 ID; + public BSPhysicsShapeType Type; + public Vector3 Position; + public Quaternion Rotation; + public Vector3 Velocity; + public Vector3 Scale; + public float Mass; + public float Buoyancy; + public System.UInt64 HullKey; + public System.UInt64 MeshKey; + public float Friction; + public float Restitution; + public float Collidable; // true of things bump into this + public float Static; // true if a static object. Otherwise gravity, etc. + public float Solid; // true if object cannot be passed through + public Vector3 Size; + + // note that bools are passed as floats since bool size changes by language and architecture + public const float numericTrue = 1f; + public const float numericFalse = 0f; + } + [StructLayout(LayoutKind.Sequential)] + public struct SweepHit + { + public UInt32 ID; + public float Fraction; + public Vector3 Normal; + public Vector3 Point; + + public bool hasHit() + { + float sum = Fraction + + Normal.X + Normal.Y + Normal.Z + + Point.X + Point.Y + Point.Z; + return (sum != 0) || (ID != 0); + } + } + [StructLayout(LayoutKind.Sequential)] + public struct RaycastHit + { + public UInt32 ID; + public float Fraction; + public Vector3 Normal; + public Vector3 Point; + + public bool hasHit() + { + float sum = Normal.X + Normal.Y + Normal.Z + Point.X + Point.Y + Point.Z; + return (sum != 0); + } + } + [StructLayout(LayoutKind.Sequential)] + public struct CollisionDesc + { + public UInt32 aID; + public UInt32 bID; + public Vector3 point; + public Vector3 normal; + public float penetration; + } + [StructLayout(LayoutKind.Sequential)] + public struct EntityProperties + { + public UInt32 ID; + public Vector3 Position; + public Quaternion Rotation; + public Vector3 Velocity; + public Vector3 Acceleration; + public Vector3 RotationalVelocity; + + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + buff.Append(""); + return buff.ToString(); + } + } + + // Format of this structure must match the definition in the C++ code + // NOTE: adding the X causes compile breaks if used. These are unused symbols + // that can be removed from both here and the unmanaged definition of this structure. + [StructLayout(LayoutKind.Sequential)] + public struct ConfigurationParameters + { + public float defaultFriction; + public float defaultDensity; + public float defaultRestitution; + public float collisionMargin; + public float gravity; + + public float maxPersistantManifoldPoolSize; + public float maxCollisionAlgorithmPoolSize; + public float shouldDisableContactPoolDynamicAllocation; + public float shouldForceUpdateAllAabbs; + public float shouldRandomizeSolverOrder; + public float shouldSplitSimulationIslands; + public float shouldEnableFrictionCaching; + public float numberOfSolverIterations; + public float useSingleSidedMeshes; + public float globalContactBreakingThreshold; + + public float physicsLoggingFrames; + + public const float numericTrue = 1f; + public const float numericFalse = 0f; + } + + // Parameters passed for the conversion of a mesh to a hull using Bullet's HACD library. + [StructLayout(LayoutKind.Sequential)] + public struct HACDParams + { + // usual default values + public float maxVerticesPerHull; // 100 + public float minClusters; // 2 + public float compacityWeight; // 0.1 + public float volumeWeight; // 0.0 + public float concavity; // 100 + public float addExtraDistPoints; // false + public float addNeighboursDistPoints; // false + public float addFacesPoints; // false + public float shouldAdjustCollisionMargin; // false + // VHACD + public float whichHACD; // zero if Bullet HACD, non-zero says VHACD + // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html + public float vHACDresolution; // 100,000 max number of voxels generated during voxelization stage + public float vHACDdepth; // 20 max number of clipping stages + public float vHACDconcavity; // 0.0025 maximum concavity + public float vHACDplaneDownsampling; // 4 granularity of search for best clipping plane + public float vHACDconvexHullDownsampling; // 4 precision of hull gen process + public float vHACDalpha; // 0.05 bias toward clipping along symmetry planes + public float vHACDbeta; // 0.05 bias toward clipping along revolution axis + public float vHACDgamma; // 0.00125 max concavity when merging + public float vHACDpca; // 0 on/off normalizing mesh before decomp + public float vHACDmode; // 0 0:voxel based, 1: tetrahedron based + public float vHACDmaxNumVerticesPerCH; // 64 max triangles per convex hull + public float vHACDminVolumePerCH; // 0.0001 sampling of generated convex hulls + } + + // The states a bullet collision object can have + public enum ActivationState : uint + { + ACTIVE_TAG = 1, + ISLAND_SLEEPING, + WANTS_DEACTIVATION, + DISABLE_DEACTIVATION, + DISABLE_SIMULATION, + } + + public enum CollisionObjectTypes : int + { + CO_COLLISION_OBJECT = 1 << 0, + CO_RIGID_BODY = 1 << 1, + CO_GHOST_OBJECT = 1 << 2, + CO_SOFT_BODY = 1 << 3, + CO_HF_FLUID = 1 << 4, + CO_USER_TYPE = 1 << 5, + } + + // Values used by Bullet and BulletSim to control object properties. + // Bullet's "CollisionFlags" has more to do with operations on the + // object (if collisions happen, if gravity effects it, ...). + public enum CollisionFlags : uint + { + CF_STATIC_OBJECT = 1 << 0, + CF_KINEMATIC_OBJECT = 1 << 1, + CF_NO_CONTACT_RESPONSE = 1 << 2, + CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3, + CF_CHARACTER_OBJECT = 1 << 4, + CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, + CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, + // Following used by BulletSim to control collisions and updates + BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, // return collision events from unmanaged to managed + BS_FLOATS_ON_WATER = 1 << 11, // the object should float at water level + BS_VEHICLE_COLLISIONS = 1 << 12, // return collisions for vehicle ground checking + BS_RETURN_ROOT_COMPOUND_SHAPE = 1 << 13, // return the pos/rot of the root shape in a compound shape + BS_NONE = 0, + BS_ALL = 0x7FFF // collision flags are a signed short + }; + + // Values f collisions groups and masks + public enum CollisionFilterGroups : uint + { + // Don't use the bit definitions!! Define the use in a + // filter/mask definition below. This way collision interactions + // are more easily found and debugged. + BNoneGroup = 0, + BDefaultGroup = 1 << 0, // 0001 + BStaticGroup = 1 << 1, // 0002 + BKinematicGroup = 1 << 2, // 0004 + BDebrisGroup = 1 << 3, // 0008 + BSensorTrigger = 1 << 4, // 0010 + BCharacterGroup = 1 << 5, // 0020 + BAllGroup = 0x0007FFF, // collision flags are a signed short + // Filter groups defined by BulletSim + BGroundPlaneGroup = 1 << 8, // 0400 + BTerrainGroup = 1 << 9, // 0800 + BRaycastGroup = 1 << 10, // 1000 + BSolidGroup = 1 << 11, // 2000 + // BLinksetGroup = xx // a linkset proper is either static or dynamic + BLinksetChildGroup = 1 << 12, // 4000 + }; + + // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 + // ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2. + public enum ConstraintParams : int + { + BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730 + BT_CONSTRAINT_STOP_ERP, + BT_CONSTRAINT_CFM, + BT_CONSTRAINT_STOP_CFM, + }; + public enum ConstraintParamAxis : int + { + AXIS_LINEAR_X = 0, + AXIS_LINEAR_Y, + AXIS_LINEAR_Z, + AXIS_ANGULAR_X, + AXIS_ANGULAR_Y, + AXIS_ANGULAR_Z, + AXIS_LINEAR_ALL = 20, // added by BulletSim so we don't have to do zillions of calls + AXIS_ANGULAR_ALL, + AXIS_ALL + }; + + public abstract class BSAPITemplate + { + // Returns the name of the underlying Bullet engine + public abstract string BulletEngineName { get; } + public abstract string BulletEngineVersion { get; protected set;} + + // Initialization and simulation + public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms, + int maxCollisions, ref CollisionDesc[] collisionArray, + int maxUpdates, ref EntityProperties[] updateArray + ); + + public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep, + out int updatedEntityCount, out int collidersCount); + + public abstract bool UpdateParameter(BulletWorld world, UInt32 localID, String parm, float value); + + public abstract void Shutdown(BulletWorld sim); + + public abstract bool PushUpdate(BulletBody obj); + + // ===================================================================================== + // Mesh, hull, shape and body creation helper routines + public abstract BulletShape CreateMeshShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices ); + + public abstract BulletShape CreateGImpactShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices ); + + public abstract BulletShape CreateHullShape(BulletWorld world, + int hullCount, float[] hulls); + + public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape, HACDParams parms); + + public abstract BulletShape BuildConvexHullShapeFromMesh(BulletWorld world, BulletShape meshShape); + + public abstract BulletShape CreateConvexHullShape(BulletWorld world, + int indicesCount, int[] indices, + int verticesCount, float[] vertices ); + + public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData); + + public abstract bool IsNativeShape(BulletShape shape); + + public abstract void SetShapeCollisionMargin(BulletShape shape, float margin); + + public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale); + + public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree); + + public abstract int GetNumberOfCompoundChildren(BulletShape cShape); + + public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot); + + public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); + + public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx); + + public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape); + + public abstract void UpdateChildTransform(BulletShape pShape, int childIndex, Vector3 pos, Quaternion rot, bool shouldRecalculateLocalAabb); + + public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape); + + public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, UInt32 id); + + public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape); + + public abstract CollisionObjectTypes GetBodyType(BulletBody obj); + + public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); + + public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); + + public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, UInt32 id, Vector3 pos, Quaternion rot); + + public abstract void DestroyObject(BulletWorld sim, BulletBody obj); + + // ===================================================================================== + public abstract BulletShape CreateGroundPlaneShape(UInt32 id, float height, float collisionMargin); + + public abstract BulletShape CreateTerrainShape(UInt32 id, Vector3 size, float minHeight, float maxHeight, float[] heightMap, + float scaleFactor, float collisionMargin); + + // ===================================================================================== + // Constraint creation and helper routines + public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + + public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 joinPoint, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + + public abstract BulletConstraint Create6DofConstraintFixed(BulletWorld world, BulletBody obj1, + Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies); + + public abstract BulletConstraint Create6DofSpringConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1loc, Quaternion frame1rot, + Vector3 frame2loc, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + + public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 pivotinA, Vector3 pivotinB, + Vector3 axisInA, Vector3 axisInB, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + + public abstract BulletConstraint CreateSliderConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies); + + public abstract BulletConstraint CreateConeTwistConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool disableCollisionsBetweenLinkedBodies); + + public abstract BulletConstraint CreateGearConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 axisInA, Vector3 axisInB, + float ratio, bool disableCollisionsBetweenLinkedBodies); + + public abstract BulletConstraint CreatePoint2PointConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 pivotInA, Vector3 pivotInB, + bool disableCollisionsBetweenLinkedBodies); + + public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse); + + public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations); + + public abstract bool SetFrames(BulletConstraint constrain, + Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot); + + public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); + + public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi); + + public abstract bool UseFrameOffset(BulletConstraint constrain, float enable); + + public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce); + + public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold); + + public const int HINGE_NOT_SPECIFIED = -1; + public abstract bool HingeSetLimits(BulletConstraint constrain, float low, float high, float softness, float bias, float relaxation); + + public abstract bool SpringEnable(BulletConstraint constrain, int index, float numericTrueFalse); + + public const int SPRING_NOT_SPECIFIED = -1; + public abstract bool SpringSetEquilibriumPoint(BulletConstraint constrain, int index, float equilibriumPoint); + + public abstract bool SpringSetStiffness(BulletConstraint constrain, int index, float stiffnesss); + + public abstract bool SpringSetDamping(BulletConstraint constrain, int index, float damping); + + public const int SLIDER_LOWER_LIMIT = 0; + public const int SLIDER_UPPER_LIMIT = 1; + public const int SLIDER_LINEAR = 2; + public const int SLIDER_ANGULAR = 3; + public abstract bool SliderSetLimits(BulletConstraint constrain, int lowerUpper, int linAng, float val); + + public const int SLIDER_SET_SOFTNESS = 4; + public const int SLIDER_SET_RESTITUTION = 5; + public const int SLIDER_SET_DAMPING = 6; + public const int SLIDER_SET_DIRECTION = 7; + public const int SLIDER_SET_LIMIT = 8; + public const int SLIDER_SET_ORTHO = 9; + public abstract bool SliderSet(BulletConstraint constrain, int softRestDamp, int dirLimOrtho, int linAng, float val); + + public abstract bool SliderMotorEnable(BulletConstraint constrain, int linAng, float numericTrueFalse); + + public const int SLIDER_MOTOR_VELOCITY = 10; + public const int SLIDER_MAX_MOTOR_FORCE = 11; + public abstract bool SliderMotor(BulletConstraint constrain, int forceVel, int linAng, float val); + + public abstract bool CalculateTransforms(BulletConstraint constrain); + + public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis); + + public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain); + + // ===================================================================================== + // btCollisionWorld entries + public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj); + + public abstract void UpdateAabbs(BulletWorld world); + + public abstract bool GetForceUpdateAllAabbs(BulletWorld world); + + public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force); + + // ===================================================================================== + // btDynamicsWorld entries + // public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot); + public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj); + + public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj); + + public abstract bool ClearCollisionProxyCache(BulletWorld world, BulletBody obj); + + public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects); + + public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain); + // ===================================================================================== + // btCollisionObject entries + public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain); + + public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict); + + public abstract bool HasAnisotripicFriction(BulletConstraint constrain); + + public abstract void SetContactProcessingThreshold(BulletBody obj, float val); + + public abstract float GetContactProcessingThreshold(BulletBody obj); + + public abstract bool IsStaticObject(BulletBody obj); + + public abstract bool IsKinematicObject(BulletBody obj); + + public abstract bool IsStaticOrKinematicObject(BulletBody obj); + + public abstract bool HasContactResponse(BulletBody obj); + + public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape); + + public abstract BulletShape GetCollisionShape(BulletBody obj); + + public abstract int GetActivationState(BulletBody obj); + + public abstract void SetActivationState(BulletBody obj, int state); + + public abstract void SetDeactivationTime(BulletBody obj, float dtime); + + public abstract float GetDeactivationTime(BulletBody obj); + + public abstract void ForceActivationState(BulletBody obj, ActivationState state); + + public abstract void Activate(BulletBody obj, bool forceActivation); + + public abstract bool IsActive(BulletBody obj); + + public abstract void SetRestitution(BulletBody obj, float val); + + public abstract float GetRestitution(BulletBody obj); + + public abstract void SetFriction(BulletBody obj, float val); + + public abstract float GetFriction(BulletBody obj); + + public abstract Vector3 GetPosition(BulletBody obj); + + public abstract Quaternion GetOrientation(BulletBody obj); + + public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation); + + // public abstract IntPtr GetBroadphaseHandle(BulletBody obj); + + // public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle); + + public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel); + + public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel); + + public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel); + + public abstract float GetHitFraction(BulletBody obj); + + public abstract void SetHitFraction(BulletBody obj, float val); + + public abstract CollisionFlags GetCollisionFlags(BulletBody obj); + + public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags); + + public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags); + + public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags); + + public abstract float GetCcdMotionThreshold(BulletBody obj); + + public abstract void SetCcdMotionThreshold(BulletBody obj, float val); + + public abstract float GetCcdSweptSphereRadius(BulletBody obj); + + public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val); + + public abstract IntPtr GetUserPointer(BulletBody obj); + + public abstract void SetUserPointer(BulletBody obj, IntPtr val); + + // ===================================================================================== + // btRigidBody entries + public abstract void ApplyGravity(BulletBody obj); + + public abstract void SetGravity(BulletBody obj, Vector3 val); + + public abstract Vector3 GetGravity(BulletBody obj); + + public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping); + + public abstract void SetLinearDamping(BulletBody obj, float lin_damping); + + public abstract void SetAngularDamping(BulletBody obj, float ang_damping); + + public abstract float GetLinearDamping(BulletBody obj); + + public abstract float GetAngularDamping(BulletBody obj); + + public abstract float GetLinearSleepingThreshold(BulletBody obj); + + public abstract void ApplyDamping(BulletBody obj, float timeStep); + + public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia); + + public abstract Vector3 GetLinearFactor(BulletBody obj); + + public abstract void SetLinearFactor(BulletBody obj, Vector3 factor); + + public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot); + + // Add a force to the object as if its mass is one. + public abstract void ApplyCentralForce(BulletBody obj, Vector3 force); + + // Set the force being applied to the object as if its mass is one. + public abstract void SetObjectForce(BulletBody obj, Vector3 force); + + public abstract Vector3 GetTotalForce(BulletBody obj); + + public abstract Vector3 GetTotalTorque(BulletBody obj); + + public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj); + + public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert); + + public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold); + + public abstract void ApplyTorque(BulletBody obj, Vector3 torque); + + // Apply force at the given point. Will add torque to the object. + public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos); + + // Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass. + public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp); + + // Apply impulse to the object's torque. Force is scaled by object's mass. + public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp); + + // Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces. + public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos); + + public abstract void ClearForces(BulletBody obj); + + public abstract void ClearAllForces(BulletBody obj); + + public abstract void UpdateInertiaTensor(BulletBody obj); + + public abstract Vector3 GetLinearVelocity(BulletBody obj); + + public abstract Vector3 GetAngularVelocity(BulletBody obj); + + public abstract void SetLinearVelocity(BulletBody obj, Vector3 val); + + public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity); + + public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos); + + public abstract void Translate(BulletBody obj, Vector3 trans); + + public abstract void UpdateDeactivation(BulletBody obj, float timeStep); + + public abstract bool WantsSleeping(BulletBody obj); + + public abstract void SetAngularFactor(BulletBody obj, float factor); + + public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor); + + public abstract Vector3 GetAngularFactor(BulletBody obj); + + public abstract bool IsInWorld(BulletWorld world, BulletBody obj); + + public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain); + + public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain); + + public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index); + + public abstract int GetNumConstraintRefs(BulletBody obj); + + public abstract bool SetCollisionGroupMask(BulletBody body, UInt32 filter, UInt32 mask); + + // ===================================================================================== + // btCollisionShape entries + + public abstract float GetAngularMotionDisc(BulletShape shape); + + public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor); + + public abstract bool IsPolyhedral(BulletShape shape); + + public abstract bool IsConvex2d(BulletShape shape); + + public abstract bool IsConvex(BulletShape shape); + + public abstract bool IsNonMoving(BulletShape shape); + + public abstract bool IsConcave(BulletShape shape); + + public abstract bool IsCompound(BulletShape shape); + + public abstract bool IsSoftBody(BulletShape shape); + + public abstract bool IsInfinite(BulletShape shape); + + public abstract void SetLocalScaling(BulletShape shape, Vector3 scale); + + public abstract Vector3 GetLocalScaling(BulletShape shape); + + public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass); + + public abstract int GetShapeType(BulletShape shape); + + public abstract void SetMargin(BulletShape shape, float val); + + public abstract float GetMargin(BulletShape shape); + + // ===================================================================================== + // Raycast + public abstract SweepHit ConvexSweepTest2(BulletWorld world, BulletBody obj, Vector3 from, Vector3 to, float margin); + + public abstract RaycastHit RayTest2(BulletWorld world, Vector3 from, Vector3 to, uint filterGroup, uint filterMask); + + // ===================================================================================== + // Debugging + public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { } + + public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { } + + public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { } + + public virtual void DumpActivationInfo(BulletWorld sim) { } + + public virtual void DumpAllInfo(BulletWorld sim) { } + + public virtual void DumpPhysicsStatistics(BulletWorld sim) { } + + public virtual void ResetBroadphasePool(BulletWorld sim) { } + + public virtual void ResetConstraintSolver(BulletWorld sim) { } + }; } diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs index f971e59166..2fc95e34fc 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs @@ -34,830 +34,852 @@ using OpenSim.Region.PhysicsModules.SharedBase; namespace OpenSim.Region.PhysicsModule.BulletS { -public sealed class BSCharacter : BSPhysObject -{ - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static readonly string LogHeader = "[BULLETS CHAR]"; - - // private bool _stopped; - private bool _grabbed; - private bool _selected; - private float _mass; - private float _avatarVolume; - private float _collisionScore; - private OMV.Vector3 _acceleration; - private int _physicsActorType; - private bool _isPhysical; - private bool _flying; - private bool _setAlwaysRun; - private bool _throttleUpdates; - private bool _floatOnWater; - private bool _kinematic; - private float _buoyancy; - - private OMV.Vector3 _size; - private float _footOffset; - - private BSActorAvatarMove m_moveActor; - private const string AvatarMoveActorName = "BSCharacter.AvatarMove"; - - private OMV.Vector3 _PIDTarget; - private float _PIDTau; - -// public override OMV.Vector3 RawVelocity -// { get { return base.RawVelocity; } -// set { -// if (value != base.RawVelocity) -// Util.PrintCallStack(); -// Console.WriteLine("Set rawvel to {0}", value); -// base.RawVelocity = value; } -// } - - // Avatars are always complete (in the physics engine sense) - public override bool IsIncomplete { get { return false; } } - - public BSCharacter( - uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, float footOffset, bool isFlying) - - : base(parent_scene, localID, avName, "BSCharacter") + public sealed class BSCharacter : BSPhysObject { - _physicsActorType = (int)ActorTypes.Agent; - RawPosition = pos; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly string LogHeader = "[BULLETS CHAR]"; - _flying = isFlying; - RawOrientation = OMV.Quaternion.Identity; - RawVelocity = vel; - _buoyancy = ComputeBuoyancyFromFlying(isFlying); - Friction = BSParam.AvatarStandingFriction; - Density = BSParam.AvatarDensity; - _isPhysical = true; + // private bool _stopped; + private bool _grabbed; + private bool _selected; + private float _mass; + private float _avatarVolume; + private float _collisionScore; + private OMV.Vector3 _acceleration; + private int _physicsActorType; + private bool _isPhysical; + private bool _flying; + private bool _setAlwaysRun; + private bool _throttleUpdates; + private bool _floatOnWater; + private bool _kinematic; + private float _buoyancy; - _footOffset = footOffset; - // Adjustments for zero X and Y made in Size() - // This also computes avatar scale, volume, and mass - SetAvatarSize(size, footOffset, true /* initializing */); + private OMV.Vector3 _size; + private float _footOffset; - DetailLog( - "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}", - LocalID, Size, Scale, Density, _avatarVolume, RawMass, pos, vel); + private BSActorAvatarMove m_moveActor; + private const string AvatarMoveActorName = "BSCharacter.AvatarMove"; - // do actual creation in taint time - PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate() + private OMV.Vector3 _PIDTarget; + private float _PIDTau; + + // public override OMV.Vector3 RawVelocity + // { get { return base.RawVelocity; } + // set { + // if (value != base.RawVelocity) + // Util.PrintCallStack(); + // Console.WriteLine("Set rawvel to {0}", value); + // base.RawVelocity = value; } + // } + + // Avatars are always complete (in the physics engine sense) + public override bool IsIncomplete { get { return false; } } + + public BSCharacter( + uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, float footOffset, bool isFlying) + + : base(parent_scene, localID, avName, "BSCharacter") { - DetailLog("{0},BSCharacter.create,taint", LocalID); - - // New body and shape into PhysBody and PhysShape - PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this); - - // The avatar's movement is controlled by this motor that speeds up and slows down - // the avatar seeking to reach the motor's target speed. - // This motor runs as a prestep action for the avatar so it will keep the avatar - // standing as well as moving. Destruction of the avatar will destroy the pre-step action. - m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); - PhysicalActors.Add(AvatarMoveActorName, m_moveActor); - - SetPhysicalProperties(); - - IsInitialized = true; - }); - return; - } - - // called when this character is being destroyed and the resources should be released - public override void Destroy() - { - IsInitialized = false; - - base.Destroy(); - - DetailLog("{0},BSCharacter.Destroy", LocalID); - PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate() - { - PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); - PhysBody.Clear(); - PhysShape.Dereference(PhysScene); - PhysShape = new BSShapeNull(); - }); - } - - private void SetPhysicalProperties() - { - PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); - - ForcePosition = RawPosition; - - // Set the velocity - if (m_moveActor != null) - m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false); - - ForceVelocity = RawVelocity; - TargetVelocity = RawVelocity; - - // This will enable or disable the flying buoyancy of the avatar. - // Needs to be reset especially when an avatar is recreated after crossing a region boundry. - Flying = _flying; - - PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); - PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin); - PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); - PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); - if (BSParam.CcdMotionThreshold > 0f) - { - PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); - PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); - } - - UpdatePhysicalMassProperties(RawMass, false); - - // Make so capsule does not fall over - PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); - - // The avatar mover sets some parameters. - PhysicalActors.Refresh(); - - PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); - - PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); - - // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); - PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); - PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); - - // Do this after the object has been added to the world - if (BSParam.AvatarToAvatarCollisionsByDefault) - PhysBody.collisionType = CollisionType.Avatar; - else - PhysBody.collisionType = CollisionType.PhantomToOthersAvatar; - - PhysBody.ApplyCollisionMask(PhysScene); - } - - public override void RequestPhysicsterseUpdate() - { - base.RequestPhysicsterseUpdate(); - } - - // No one calls this method so I don't know what it could possibly mean - public override bool Stopped { get { return false; } } - - public override OMV.Vector3 Size { - get - { - return _size; - } - - set { - setAvatarSize(value, _footOffset); - } - } - - // OpenSim 0.9 introduces a common avatar size computation - public override void setAvatarSize(OMV.Vector3 size, float feetOffset) - { - SetAvatarSize(size, feetOffset, false /* initializing */); - } - - // Internal version that, if initializing, doesn't do all the updating of the physics engine - public void SetAvatarSize(OMV.Vector3 size, float feetOffset, bool initializing) - { - OMV.Vector3 newSize = size; - if (newSize.IsFinite()) - { - // Old versions of ScenePresence passed only the height. If width and/or depth are zero, - // replace with the default values. - if (newSize.X == 0f) newSize.X = BSParam.AvatarCapsuleDepth; - if (newSize.Y == 0f) newSize.Y = BSParam.AvatarCapsuleWidth; - - if (newSize.X < 0.01f) newSize.X = 0.01f; - if (newSize.Y < 0.01f) newSize.Y = 0.01f; - if (newSize.Z < 0.01f) newSize.Z = BSParam.AvatarCapsuleHeight; - } - else - { - newSize = new OMV.Vector3(BSParam.AvatarCapsuleDepth, BSParam.AvatarCapsuleWidth, BSParam.AvatarCapsuleHeight); - } - - // This is how much the avatar size is changing. Positive means getting bigger. - // The avatar altitude must be adjusted for this change. - float heightChange = newSize.Z - Size.Z; - - _size = newSize; - - Scale = ComputeAvatarScale(Size); - ComputeAvatarVolumeAndMass(); - DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", - LocalID, _size, Scale, Density, _avatarVolume, RawMass); - - PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate() - { - if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) + _physicsActorType = (int)ActorTypes.Agent; + RawPosition = pos; + + _flying = isFlying; + RawOrientation = OMV.Quaternion.Identity; + RawVelocity = vel; + _buoyancy = ComputeBuoyancyFromFlying(isFlying); + Friction = BSParam.AvatarStandingFriction; + Density = BSParam.AvatarDensity; + _isPhysical = true; + + _footOffset = footOffset; + // Adjustments for zero X and Y made in Size() + // This also computes avatar scale, volume, and mass + SetAvatarSize(size, footOffset, true /* initializing */); + + DetailLog( + "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}", + LocalID, Size, Scale, Density, _avatarVolume, RawMass, pos, vel); + + // do actual creation in taint time + PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate() { - PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); - UpdatePhysicalMassProperties(RawMass, true); + DetailLog("{0},BSCharacter.create,taint", LocalID); + + // New body and shape into PhysBody and PhysShape + PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this); + + // The avatar's movement is controlled by this motor that speeds up and slows down + // the avatar seeking to reach the motor's target speed. + // This motor runs as a prestep action for the avatar so it will keep the avatar + // standing as well as moving. Destruction of the avatar will destroy the pre-step action. + m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); + PhysicalActors.Add(AvatarMoveActorName, m_moveActor); + + SetPhysicalProperties(); + + IsInitialized = true; + }); + return; + } - // Adjust the avatar's position to account for the increase/decrease in size - ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f); + // called when this character is being destroyed and the resources should be released + public override void Destroy() + { + IsInitialized = false; + + base.Destroy(); + + DetailLog("{0},BSCharacter.Destroy", LocalID); + PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate() + { + PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); + PhysBody.Clear(); + PhysShape.Dereference(PhysScene); + PhysShape = new BSShapeNull(); + }); + } - // Make sure this change appears as a property update event - PhysScene.PE.PushUpdate(PhysBody); + private void SetPhysicalProperties() + { + PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); + + ForcePosition = RawPosition; + + // Set the velocity + if (m_moveActor != null) + m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false); + + ForceVelocity = RawVelocity; + TargetVelocity = RawVelocity; + + // This will enable or disable the flying buoyancy of the avatar. + // Needs to be reset especially when an avatar is recreated after crossing a region boundry. + Flying = _flying; + + PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); + PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin); + PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); + PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); + if (BSParam.CcdMotionThreshold > 0f) + { + PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); + PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); } - }); - } + + UpdatePhysicalMassProperties(RawMass, false); + + // Make so capsule does not fall over + PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); + + // The avatar mover sets some parameters. + PhysicalActors.Refresh(); + + PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); + + PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); + + // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); + PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); + PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); + + // Do this after the object has been added to the world + if (BSParam.AvatarToAvatarCollisionsByDefault) + PhysBody.collisionType = CollisionType.Avatar; + else + PhysBody.collisionType = CollisionType.PhantomToOthersAvatar; + + PhysBody.ApplyCollisionMask(PhysScene); + } + + public override void RequestPhysicsterseUpdate() + { + base.RequestPhysicsterseUpdate(); + } + + // No one calls this method so I don't know what it could possibly mean + public override bool Stopped { get { return false; } } + + public override OMV.Vector3 Size { + get + { + return _size; + } + + set { + setAvatarSize(value, _footOffset); + } + } + + // OpenSim 0.9 introduces a common avatar size computation + public override void setAvatarSize(OMV.Vector3 size, float feetOffset) + { + SetAvatarSize(size, feetOffset, false /* initializing */); + } + + // Internal version that, if initializing, doesn't do all the updating of the physics engine + public void SetAvatarSize(OMV.Vector3 size, float feetOffset, bool initializing) + { + OMV.Vector3 newSize = size; + if (newSize.IsFinite()) + { + // Old versions of ScenePresence passed only the height. If width and/or depth are zero, + // replace with the default values. + if (newSize.X == 0f) newSize.X = BSParam.AvatarCapsuleDepth; + if (newSize.Y == 0f) newSize.Y = BSParam.AvatarCapsuleWidth; + + if (newSize.X < 0.01f) newSize.X = 0.01f; + if (newSize.Y < 0.01f) newSize.Y = 0.01f; + if (newSize.Z < 0.01f) newSize.Z = BSParam.AvatarCapsuleHeight; + } + else + { + newSize = new OMV.Vector3(BSParam.AvatarCapsuleDepth, BSParam.AvatarCapsuleWidth, BSParam.AvatarCapsuleHeight); + } + + // This is how much the avatar size is changing. Positive means getting bigger. + // The avatar altitude must be adjusted for this change. + float heightChange = newSize.Z - Size.Z; + + _size = newSize; + + Scale = ComputeAvatarScale(Size); + ComputeAvatarVolumeAndMass(); + DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", + LocalID, _size, Scale, Density, _avatarVolume, RawMass); + + PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate() + { + if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) + { + PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); + UpdatePhysicalMassProperties(RawMass, true); + + // Adjust the avatar's position to account for the increase/decrease in size + ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f); + + // Make sure this change appears as a property update event + PhysScene.PE.PushUpdate(PhysBody); + } + }); + } public override PrimitiveBaseShape Shape - { - set { BaseShape = value; } - } - - public override bool Grabbed { - set { _grabbed = value; } - } - public override bool Selected { - set { _selected = value; } - } - public override bool IsSelected - { - get { return _selected; } - } - public override void CrossingFailure() { return; } - public override void link(PhysicsActor obj) { return; } - public override void delink() { return; } - - // Set motion values to zero. - // Do it to the properties so the values get set in the physics engine. - // Push the setting of the values to the viewer. - // Called at taint time! - public override void ZeroMotion(bool inTaintTime) - { - RawVelocity = OMV.Vector3.Zero; - _acceleration = OMV.Vector3.Zero; - RawRotationalVelocity = OMV.Vector3.Zero; - - // Zero some other properties directly into the physics engine - PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() { - if (PhysBody.HasPhysicalBody) - PhysScene.PE.ClearAllForces(PhysBody); - }); - } - - public override void ZeroAngularMotion(bool inTaintTime) - { - RawRotationalVelocity = OMV.Vector3.Zero; - - PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() - { - if (PhysBody.HasPhysicalBody) - { - PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); - PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); - // The next also get rid of applied linear force but the linear velocity is untouched. - PhysScene.PE.ClearForces(PhysBody); - } - }); - } - - - public override void LockAngularMotion(byte axislocks) { return; } - - public override OMV.Vector3 Position { - get { - // Don't refetch the position because this function is called a zillion times - // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); - return RawPosition; + set { BaseShape = value; } } - set { - RawPosition = value; - PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate() + public override bool Grabbed { + set { _grabbed = value; } + } + + public override bool Selected { + set { _selected = value; } + } + + public override bool IsSelected + { + get { return _selected; } + } + + public override void CrossingFailure() { return; } + public override void link(PhysicsActor obj) { return; } + public override void delink() { return; } + + // Set motion values to zero. + // Do it to the properties so the values get set in the physics engine. + // Push the setting of the values to the viewer. + // Called at taint time! + public override void ZeroMotion(bool inTaintTime) + { + RawVelocity = OMV.Vector3.Zero; + _acceleration = OMV.Vector3.Zero; + RawRotationalVelocity = OMV.Vector3.Zero; + + // Zero some other properties directly into the physics engine + PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() { - DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); - PositionSanityCheck(); - ForcePosition = RawPosition; + if (PhysBody.HasPhysicalBody) + PhysScene.PE.ClearAllForces(PhysBody); }); } - } - public override OMV.Vector3 ForcePosition { - get { - RawPosition = PhysScene.PE.GetPosition(PhysBody); - return RawPosition; - } - set { - RawPosition = value; - if (PhysBody.HasPhysicalBody) + + public override void ZeroAngularMotion(bool inTaintTime) + { + RawRotationalVelocity = OMV.Vector3.Zero; + + PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() { - PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); + PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); + // The next also get rid of applied linear force but the linear velocity is untouched. + PhysScene.PE.ClearForces(PhysBody); + } + }); + } + + public override void LockAngularMotion(byte axislocks) { return; } + + public override OMV.Vector3 Position { + get { + // Don't refetch the position because this function is called a zillion times + // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); + return RawPosition; + } + set { + RawPosition = value; + + PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate() + { + DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); + PositionSanityCheck(); + ForcePosition = RawPosition; + }); } } - } - // Check that the current position is sane and, if not, modify the position to make it so. - // Check for being below terrain or on water. - // Returns 'true' of the position was made sane by some action. - private bool PositionSanityCheck() - { - bool ret = false; - - // TODO: check for out of bounds - if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) - { - // The character is out of the known/simulated area. - // Force the avatar position to be within known. ScenePresence will use the position - // plus the velocity to decide if the avatar is moving out of the region. - RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); - DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); - return true; + public override OMV.Vector3 ForcePosition { + get { + RawPosition = PhysScene.PE.GetPosition(PhysBody); + return RawPosition; + } + set { + RawPosition = value; + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); + } + } } - // If below the ground, move the avatar up - float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); - if (Position.Z < terrainHeight) + // Check that the current position is sane and, if not, modify the position to make it so. + // Check for being below terrain or on water. + // Returns 'true' of the position was made sane by some action. + private bool PositionSanityCheck() { - DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); - RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters); - ret = true; - } - if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) - { - float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); - if (Position.Z < waterHeight) + bool ret = false; + + // TODO: check for out of bounds + if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) { - RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight); + // The character is out of the known/simulated area. + // Force the avatar position to be within known. ScenePresence will use the position + // plus the velocity to decide if the avatar is moving out of the region. + RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); + DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); + return true; + } + + // If below the ground, move the avatar up + float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); + if (Position.Z < terrainHeight) + { + DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); + RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters); ret = true; } - } - - return ret; - } - - // A version of the sanity check that also makes sure a new position value is - // pushed back to the physics engine. This routine would be used by anyone - // who is not already pushing the value. - private bool PositionSanityCheck(bool inTaintTime) - { - bool ret = false; - if (PositionSanityCheck()) - { - // The new position value must be pushed into the physics engine but we can't - // just assign to "Position" because of potential call loops. - PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate() + if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) { - DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); - ForcePosition = RawPosition; - }); - ret = true; - } - return ret; - } - - public override float Mass { get { return _mass; } } - - // used when we only want this prim's mass and not the linkset thing - public override float RawMass { - get {return _mass; } - } - public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) - { - OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); - PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia); - } - - public override OMV.Vector3 Force { - get { return RawForce; } - set { - RawForce = value; - // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); - PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate() - { - DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); - if (PhysBody.HasPhysicalBody) - PhysScene.PE.SetObjectForce(PhysBody, RawForce); - }); - } - } - - // Avatars don't do vehicles - public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } } - public override void VehicleFloatParam(int param, float value) { } - public override void VehicleVectorParam(int param, OMV.Vector3 value) {} - public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } - public override void VehicleFlags(int param, bool remove) { } - - // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more - public override void SetVolumeDetect(int param) { return; } - public override bool IsVolumeDetect { get { return false; } } - - public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } - public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } - - // PhysicsActor.TargetVelocity - // Sets the target in the motor. This starts the changing of the avatar's velocity. - public override OMV.Vector3 TargetVelocity - { - get - { - return base.m_targetVelocity; - } - set - { - DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); - OMV.Vector3 targetVel = value; - if (!_flying) - { - if (_setAlwaysRun) - targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f); - else - if (BSParam.AvatarWalkVelocityFactor != 1f) - targetVel *= new OMV.Vector3(BSParam.AvatarWalkVelocityFactor, BSParam.AvatarWalkVelocityFactor, 1f); + float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); + if (Position.Z < waterHeight) + { + RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight); + ret = true; + } } - base.m_targetVelocity = targetVel; - - if (m_moveActor != null) - m_moveActor.SetVelocityAndTarget(RawVelocity, base.m_targetVelocity, false /* inTaintTime */); + + return ret; } - } - // Directly setting velocity means this is what the user really wants now. - public override OMV.Vector3 Velocity { - get { return RawVelocity; } - set { + + // A version of the sanity check that also makes sure a new position value is + // pushed back to the physics engine. This routine would be used by anyone + // who is not already pushing the value. + private bool PositionSanityCheck(bool inTaintTime) + { + bool ret = false; + if (PositionSanityCheck()) + { + // The new position value must be pushed into the physics engine but we can't + // just assign to "Position" because of potential call loops. + PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate() + { + DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); + ForcePosition = RawPosition; + }); + ret = true; + } + return ret; + } + + public override float Mass { get { return _mass; } } + + // used when we only want this prim's mass and not the linkset thing + public override float RawMass { + get {return _mass; } + } + + public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) + { + OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); + PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia); + } + + public override OMV.Vector3 Force { + get { return RawForce; } + set { + RawForce = value; + // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); + PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate() + { + DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); + if (PhysBody.HasPhysicalBody) + PhysScene.PE.SetObjectForce(PhysBody, RawForce); + }); + } + } + + // Avatars don't do vehicles + public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } } + public override void VehicleFloatParam(int param, float value) { } + public override void VehicleVectorParam(int param, OMV.Vector3 value) {} + public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } + public override void VehicleFlags(int param, bool remove) { } + + // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more + public override void SetVolumeDetect(int param) { return; } + public override bool IsVolumeDetect { get { return false; } } + + public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } + public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } + + // PhysicsActor.TargetVelocity + // Sets the target in the motor. This starts the changing of the avatar's velocity. + public override OMV.Vector3 TargetVelocity + { + get + { + return base.m_targetVelocity; + } + set + { + DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); + OMV.Vector3 targetVel = value; + if (!_flying) + { + if (_setAlwaysRun) + targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f); + else + if (BSParam.AvatarWalkVelocityFactor != 1f) + targetVel *= new OMV.Vector3(BSParam.AvatarWalkVelocityFactor, BSParam.AvatarWalkVelocityFactor, 1f); + } + base.m_targetVelocity = targetVel; + + if (m_moveActor != null) + m_moveActor.SetVelocityAndTarget(RawVelocity, base.m_targetVelocity, false /* inTaintTime */); + } + } + + // Directly setting velocity means this is what the user really wants now. + public override OMV.Vector3 Velocity { + get { return RawVelocity; } + set { + if (m_moveActor != null) + { + // m_moveActor.SetVelocityAndTarget(OMV.Vector3.Zero, OMV.Vector3.Zero, false /* inTaintTime */); + m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false /* inTaintTime */); + } + base.Velocity = value; + } + } + + // SetMomentum just sets the velocity without a target. We need to stop the movement actor if a character. + public override void SetMomentum(OMV.Vector3 momentum) + { if (m_moveActor != null) { // m_moveActor.SetVelocityAndTarget(OMV.Vector3.Zero, OMV.Vector3.Zero, false /* inTaintTime */); m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false /* inTaintTime */); } - base.Velocity = value; + base.SetMomentum(momentum); } - } - // SetMomentum just sets the velocity without a target. We need to stop the movement actor if a character. - public override void SetMomentum(OMV.Vector3 momentum) - { - if (m_moveActor != null) + public override OMV.Vector3 ForceVelocity { + get { return RawVelocity; } + set { + DetailLog("{0},BSCharacter.ForceVelocity.set={1}", LocalID, value); + + RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); + PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); + PhysScene.PE.Activate(PhysBody, true); + } + } + + public override OMV.Vector3 Torque { + get { return RawTorque; } + set { RawTorque = value; + } + } + + public override float CollisionScore { + get { return _collisionScore; } + set { _collisionScore = value; + } + } + + public override OMV.Vector3 Acceleration { + get { return _acceleration; } + set { _acceleration = value; } + } + + public override OMV.Quaternion Orientation { + get { return RawOrientation; } + set { + // Orientation is set zillions of times when an avatar is walking. It's like + // the viewer doesn't trust us. + if (RawOrientation != value) + { + RawOrientation = value; + PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate() + { + // Bullet assumes we know what we are doing when forcing orientation + // so it lets us go against all the rules and just compensates for them later. + // This forces rotation to be only around the Z axis and doesn't change any of the other axis. + // This keeps us from flipping the capsule over which the veiwer does not understand. + float oRoll, oPitch, oYaw; + RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw); + OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw); + // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}", + // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation, + // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation); + ForceOrientation = trimmedOrientation; + }); + } + } + } + + // Go directly to Bullet to get/set the value. + public override OMV.Quaternion ForceOrientation { - // m_moveActor.SetVelocityAndTarget(OMV.Vector3.Zero, OMV.Vector3.Zero, false /* inTaintTime */); - m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false /* inTaintTime */); - } - base.SetMomentum(momentum); - } - - public override OMV.Vector3 ForceVelocity { - get { return RawVelocity; } - set { - DetailLog("{0},BSCharacter.ForceVelocity.set={1}", LocalID, value); - - RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); - PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); - PhysScene.PE.Activate(PhysBody, true); - } - } - - public override OMV.Vector3 Torque { - get { return RawTorque; } - set { RawTorque = value; - } - } - - public override float CollisionScore { - get { return _collisionScore; } - set { _collisionScore = value; - } - } - public override OMV.Vector3 Acceleration { - get { return _acceleration; } - set { _acceleration = value; } - } - public override OMV.Quaternion Orientation { - get { return RawOrientation; } - set { - // Orientation is set zillions of times when an avatar is walking. It's like - // the viewer doesn't trust us. - if (RawOrientation != value) + get + { + RawOrientation = PhysScene.PE.GetOrientation(PhysBody); + return RawOrientation; + } + set { RawOrientation = value; - PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate() + if (PhysBody.HasPhysicalBody) { - // Bullet assumes we know what we are doing when forcing orientation - // so it lets us go against all the rules and just compensates for them later. - // This forces rotation to be only around the Z axis and doesn't change any of the other axis. - // This keeps us from flipping the capsule over which the veiwer does not understand. - float oRoll, oPitch, oYaw; - RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw); - OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw); - // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}", - // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation, - // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation); - ForceOrientation = trimmedOrientation; + // RawPosition = PhysicsScene.PE.GetPosition(BSBody); + PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); + } + } + } + + public override int PhysicsActorType { + get { return _physicsActorType; } + set { _physicsActorType = value; + } + } + + public override bool IsPhysical { + get { return _isPhysical; } + set { _isPhysical = value; + } + } + + public override bool IsSolid { + get { return true; } + } + + public override bool IsStatic { + get { return false; } + } + + public override bool IsPhysicallyActive { + get { return true; } + } + + public override bool Flying { + get { return _flying; } + set { + _flying = value; + + // simulate flying by changing the effect of gravity + Buoyancy = ComputeBuoyancyFromFlying(_flying); + } + } + + // Flying is implimented by changing the avatar's buoyancy. + // Would this be done better with a vehicle type? + private float ComputeBuoyancyFromFlying(bool ifFlying) { + return ifFlying ? 1f : 0f; + } + + public override bool + SetAlwaysRun { + get { return _setAlwaysRun; } + set { _setAlwaysRun = value; } + } + + public override bool ThrottleUpdates { + get { return _throttleUpdates; } + set { _throttleUpdates = value; } + } + + public override bool FloatOnWater { + set { + _floatOnWater = value; + PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate() + { + if (PhysBody.HasPhysicalBody) + { + if (_floatOnWater) + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); + else + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); + } }); } } - } - // Go directly to Bullet to get/set the value. - public override OMV.Quaternion ForceOrientation - { - get - { - RawOrientation = PhysScene.PE.GetOrientation(PhysBody); - return RawOrientation; + + public override bool Kinematic { + get { return _kinematic; } + set { _kinematic = value; } } - set - { - RawOrientation = value; - if (PhysBody.HasPhysicalBody) - { - // RawPosition = PhysicsScene.PE.GetPosition(BSBody); - PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); + + // neg=fall quickly, 0=1g, 1=0g, pos=float up + public override float Buoyancy { + get { return _buoyancy; } + set { _buoyancy = value; + PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate() + { + DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); + ForceBuoyancy = _buoyancy; + }); } } - } - public override int PhysicsActorType { - get { return _physicsActorType; } - set { _physicsActorType = value; - } - } - public override bool IsPhysical { - get { return _isPhysical; } - set { _isPhysical = value; - } - } - public override bool IsSolid { - get { return true; } - } - public override bool IsStatic { - get { return false; } - } - public override bool IsPhysicallyActive { - get { return true; } - } - public override bool Flying { - get { return _flying; } - set { - _flying = value; - // simulate flying by changing the effect of gravity - Buoyancy = ComputeBuoyancyFromFlying(_flying); - } - } - // Flying is implimented by changing the avatar's buoyancy. - // Would this be done better with a vehicle type? - private float ComputeBuoyancyFromFlying(bool ifFlying) { - return ifFlying ? 1f : 0f; - } - public override bool - SetAlwaysRun { - get { return _setAlwaysRun; } - set { _setAlwaysRun = value; } - } - public override bool ThrottleUpdates { - get { return _throttleUpdates; } - set { _throttleUpdates = value; } - } - public override bool FloatOnWater { - set { - _floatOnWater = value; - PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate() - { + public override float ForceBuoyancy { + get { return _buoyancy; } + set { + _buoyancy = value; + DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); + // Buoyancy is faked by changing the gravity applied to the object + float grav = BSParam.Gravity * (1f - _buoyancy); + Gravity = new OMV.Vector3(0f, 0f, grav); if (PhysBody.HasPhysicalBody) - { - if (_floatOnWater) - CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); - else - CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); - } - }); - } - } - public override bool Kinematic { - get { return _kinematic; } - set { _kinematic = value; } - } - // neg=fall quickly, 0=1g, 1=0g, pos=float up - public override float Buoyancy { - get { return _buoyancy; } - set { _buoyancy = value; - PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate() - { - DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); - ForceBuoyancy = _buoyancy; - }); - } - } - public override float ForceBuoyancy { - get { return _buoyancy; } - set { - _buoyancy = value; - DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); - // Buoyancy is faked by changing the gravity applied to the object - float grav = BSParam.Gravity * (1f - _buoyancy); - Gravity = new OMV.Vector3(0f, 0f, grav); - if (PhysBody.HasPhysicalBody) - PhysScene.PE.SetGravity(PhysBody, Gravity); - } - } - - // Used for MoveTo - public override OMV.Vector3 PIDTarget { - set { _PIDTarget = value; } - } - - public override bool PIDActive { get; set; } - - public override float PIDTau { - set { _PIDTau = value; } - } - - public override void AddForce(OMV.Vector3 force, bool pushforce) - { - // Since this force is being applied in only one step, make this a force per second. - OMV.Vector3 addForce = force; - - // The interaction of this force with the simulator rate and collision occurance is tricky. - // ODE multiplies the force by 100 - // ubODE multiplies the force by 5.3 - // BulletSim, after much in-world testing, thinks it gets a similar effect by multiplying mass*0.315f - // This number could be a feature of friction or timing, but it seems to move avatars the same as ubODE - addForce *= Mass * BSParam.AvatarAddForcePushFactor; - - DetailLog("{0},BSCharacter.addForce,call,force={1},addForce={2},push={3},mass={4}", LocalID, force, addForce, pushforce, Mass); - AddForce(false, addForce); - } - - public override void AddForce(bool inTaintTime, OMV.Vector3 force) { - if (force.IsFinite()) - { - OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); - // DetailLog("{0},BSCharacter.addForce,call,force={1},push={2},inTaint={3}", LocalID, addForce, pushforce, inTaintTime); - - PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate() - { - // Bullet adds this central force to the total force for this tick - // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); - if (PhysBody.HasPhysicalBody) - { - // Bullet adds this central force to the total force for this tick. - // Deep down in Bullet: - // linearVelocity += totalForce / mass * timeStep; - PhysScene.PE.ApplyCentralForce(PhysBody, addForce); - PhysScene.PE.Activate(PhysBody, true); - } - if (m_moveActor != null) - { - m_moveActor.SuppressStationayCheckUntilLowVelocity(BSParam.AvatarAddForceFrames); - } - }); - } - else - { - m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID); - return; - } - } - - public override void AddAngularForce(bool inTaintTime, OMV.Vector3 force) { - } - - // The avatar's physical shape (whether capsule or cube) is unit sized. BulletSim sets - // the scale of that unit shape to create the avatars full size. - private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) - { - OMV.Vector3 newScale = size; - - if (BSParam.AvatarUseBefore09SizeComputation) - { - - // Bullet's capsule total height is the "passed height + radius * 2"; - // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1) - // The number we pass in for 'scaling' is the multiplier to get that base - // shape to be the size desired. - // So, when creating the scale for the avatar height, we take the passed height - // (size.Z) and remove the caps. - // An oddity of the Bullet capsule implementation is that it presumes the Y - // dimension is the radius of the capsule. Even though some of the code allows - // for a asymmetrical capsule, other parts of the code presume it is cylindrical. - - // Scale is multiplier of radius with one of "0.5" - - float heightAdjust = BSParam.AvatarHeightMidFudge; - if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) - { - const float AVATAR_LOW = 1.1f; - const float AVATAR_MID = 1.775f; // 1.87f - const float AVATAR_HI = 2.45f; - // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m. - float midHeightOffset = size.Z - AVATAR_MID; - if (midHeightOffset < 0f) - { - // Small avatar. Add the adjustment based on the distance from midheight - heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge; - } - else - { - // Large avatar. Add the adjustment based on the distance from midheight - heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge; - } + PhysScene.PE.SetGravity(PhysBody, Gravity); } - if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule) + } + + // Used for MoveTo + public override OMV.Vector3 PIDTarget { + set { _PIDTarget = value; } + } + + public override bool PIDActive { get; set; } + + public override float PIDTau { + set { _PIDTau = value; } + } + + public override void AddForce(OMV.Vector3 force, bool pushforce) + { + // Since this force is being applied in only one step, make this a force per second. + OMV.Vector3 addForce = force; + + // The interaction of this force with the simulator rate and collision occurance is tricky. + // ODE multiplies the force by 100 + // ubODE multiplies the force by 5.3 + // BulletSim, after much in-world testing, thinks it gets a similar effect by multiplying mass*0.315f + // This number could be a feature of friction or timing, but it seems to move avatars the same as ubODE + addForce *= Mass * BSParam.AvatarAddForcePushFactor; + + DetailLog("{0},BSCharacter.addForce,call,force={1},addForce={2},push={3},mass={4}", LocalID, force, addForce, pushforce, Mass); + AddForce(false, addForce); + } + + public override void AddForce(bool inTaintTime, OMV.Vector3 force) + { + if (force.IsFinite()) { - newScale.X = size.X / 2f; - newScale.Y = size.Y / 2f; - // The total scale height is the central cylindar plus the caps on the two ends. - newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f; + OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); + // DetailLog("{0},BSCharacter.addForce,call,force={1},push={2},inTaint={3}", LocalID, addForce, pushforce, inTaintTime); + + PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate() + { + // Bullet adds this central force to the total force for this tick + // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); + if (PhysBody.HasPhysicalBody) + { + // Bullet adds this central force to the total force for this tick. + // Deep down in Bullet: + // linearVelocity += totalForce / mass * timeStep; + PhysScene.PE.ApplyCentralForce(PhysBody, addForce); + PhysScene.PE.Activate(PhysBody, true); + } + if (m_moveActor != null) + { + m_moveActor.SuppressStationayCheckUntilLowVelocity(BSParam.AvatarAddForceFrames); + } + }); } else { - newScale.Z = size.Z + heightAdjust; + m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID); + return; } - // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale); - - // If smaller than the endcaps, just fake like we're almost that small - if (newScale.Z < 0) - newScale.Z = 0.1f; - - DetailLog("{0},BSCharacter.ComputeAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}", - LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale); } - else + + public override void AddAngularForce(bool inTaintTime, OMV.Vector3 force) { + } + + // The avatar's physical shape (whether capsule or cube) is unit sized. BulletSim sets + // the scale of that unit shape to create the avatars full size. + private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) { - newScale.Z = size.Z + _footOffset; - DetailLog("{0},BSCharacter.ComputeAvatarScale,using newScale={1}, footOffset={2}", LocalID, newScale, _footOffset); + OMV.Vector3 newScale = size; + + if (BSParam.AvatarUseBefore09SizeComputation) + { + + // Bullet's capsule total height is the "passed height + radius * 2"; + // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1) + // The number we pass in for 'scaling' is the multiplier to get that base + // shape to be the size desired. + // So, when creating the scale for the avatar height, we take the passed height + // (size.Z) and remove the caps. + // An oddity of the Bullet capsule implementation is that it presumes the Y + // dimension is the radius of the capsule. Even though some of the code allows + // for a asymmetrical capsule, other parts of the code presume it is cylindrical. + + // Scale is multiplier of radius with one of "0.5" + + float heightAdjust = BSParam.AvatarHeightMidFudge; + if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) + { + const float AVATAR_LOW = 1.1f; + const float AVATAR_MID = 1.775f; // 1.87f + const float AVATAR_HI = 2.45f; + // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m. + float midHeightOffset = size.Z - AVATAR_MID; + if (midHeightOffset < 0f) + { + // Small avatar. Add the adjustment based on the distance from midheight + heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge; + } + else + { + // Large avatar. Add the adjustment based on the distance from midheight + heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge; + } + } + if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule) + { + newScale.X = size.X / 2f; + newScale.Y = size.Y / 2f; + // The total scale height is the central cylindar plus the caps on the two ends. + newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f; + } + else + { + newScale.Z = size.Z + heightAdjust; + } + // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale); + + // If smaller than the endcaps, just fake like we're almost that small + if (newScale.Z < 0) + newScale.Z = 0.1f; + + DetailLog("{0},BSCharacter.ComputeAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}", + LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale); + } + else + { + newScale.Z = size.Z + _footOffset; + DetailLog("{0},BSCharacter.ComputeAvatarScale,using newScale={1}, footOffset={2}", LocalID, newScale, _footOffset); + } + + return newScale; } - return newScale; - } - - // set _avatarVolume and _mass based on capsule size, _density and Scale - private void ComputeAvatarVolumeAndMass() - { - if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule) + // set _avatarVolume and _mass based on capsule size, _density and Scale + private void ComputeAvatarVolumeAndMass() { - _avatarVolume = (float)( - Math.PI - * Size.X / 2f - * Size.Y / 2f // the area of capsule cylinder - * Size.Z // times height of capsule cylinder - + 1.33333333f - * Math.PI - * Size.X / 2f - * Math.Min(Size.X, Size.Y) / 2 - * Size.Y / 2f // plus the volume of the capsule end caps - ); + if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule) + { + _avatarVolume = (float)( + Math.PI + * Size.X / 2f + * Size.Y / 2f // the area of capsule cylinder + * Size.Z // times height of capsule cylinder + + 1.33333333f + * Math.PI + * Size.X / 2f + * Math.Min(Size.X, Size.Y) / 2 + * Size.Y / 2f // plus the volume of the capsule end caps + ); + } + else + { + _avatarVolume = Size.X * Size.Y * Size.Z; + } + _mass = Density * BSParam.DensityScaleFactor * _avatarVolume; } - else + + // The physics engine says that properties have updated. Update same and inform + // the world that things have changed. + public override void UpdateProperties(EntityProperties entprop) { - _avatarVolume = Size.X * Size.Y * Size.Z; + // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. + TriggerPreUpdatePropertyAction(ref entprop); + + RawPosition = entprop.Position; + RawOrientation = entprop.Rotation; + + // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar + // and will send agent updates to the clients if velocity changes by more than + // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many + // extra updates. + // + // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to + // avatar movement rather than removes it. The larger the threshold, the bigger the jitter. + // This is most noticeable in level flight and can be seen with + // the "show updates" option in a viewer. With an update threshold, the RawVelocity cycles between a lower + // bound and an upper bound, where the difference between the two is enough to trigger a large delta v update + // and subsequently trigger an update in ScenePresence.SendTerseUpdateToAllClients(). The cause of this cycle (feedback?) + // has not yet been identified. + // + // If there is a threshold below 0.4 or no threshold check at all (as in ODE), then RawVelocity stays constant and extra + // updates are not triggered in ScenePresence.SendTerseUpdateToAllClients(). + // if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f)) + RawVelocity = entprop.Velocity; + + _acceleration = entprop.Acceleration; + RawRotationalVelocity = entprop.RotationalVelocity; + + // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. + if (PositionSanityCheck(true)) + { + DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition); + entprop.Position = RawPosition; + } + + // remember the current and last set values + LastEntityProperties = CurrentEntityProperties; + CurrentEntityProperties = entprop; + + // Tell the linkset about value changes + // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); + + // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. + // PhysScene.PostUpdate(this); + + DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", + LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, RawRotationalVelocity); } - _mass = Density * BSParam.DensityScaleFactor * _avatarVolume; - } - - // The physics engine says that properties have updated. Update same and inform - // the world that things have changed. - public override void UpdateProperties(EntityProperties entprop) - { - // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. - TriggerPreUpdatePropertyAction(ref entprop); - - RawPosition = entprop.Position; - RawOrientation = entprop.Rotation; - - // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar - // and will send agent updates to the clients if velocity changes by more than - // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many - // extra updates. - // - // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to - // avatar movement rather than removes it. The larger the threshold, the bigger the jitter. - // This is most noticeable in level flight and can be seen with - // the "show updates" option in a viewer. With an update threshold, the RawVelocity cycles between a lower - // bound and an upper bound, where the difference between the two is enough to trigger a large delta v update - // and subsequently trigger an update in ScenePresence.SendTerseUpdateToAllClients(). The cause of this cycle (feedback?) - // has not yet been identified. - // - // If there is a threshold below 0.4 or no threshold check at all (as in ODE), then RawVelocity stays constant and extra - // updates are not triggered in ScenePresence.SendTerseUpdateToAllClients(). -// if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f)) - RawVelocity = entprop.Velocity; - - _acceleration = entprop.Acceleration; - RawRotationalVelocity = entprop.RotationalVelocity; - - // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. - if (PositionSanityCheck(true)) - { - DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition); - entprop.Position = RawPosition; - } - - // remember the current and last set values - LastEntityProperties = CurrentEntityProperties; - CurrentEntityProperties = entprop; - - // Tell the linkset about value changes - // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); - - // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. - // PhysScene.PostUpdate(this); - - DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", - LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, RawRotationalVelocity); } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs index e42e868853..9feb1fbb3d 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint.cs @@ -31,114 +31,113 @@ using OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { - -public abstract class BSConstraint : IDisposable -{ - private static string LogHeader = "[BULLETSIM CONSTRAINT]"; - - protected BulletWorld m_world; - protected BSScene PhysicsScene; - protected BulletBody m_body1; - protected BulletBody m_body2; - protected BulletConstraint m_constraint; - protected bool m_enabled = false; - - public BulletBody Body1 { get { return m_body1; } } - public BulletBody Body2 { get { return m_body2; } } - public BulletConstraint Constraint { get { return m_constraint; } } - public abstract ConstraintType Type { get; } - public bool IsEnabled { get { return m_enabled; } } - - public BSConstraint(BulletWorld world) + public abstract class BSConstraint : IDisposable { - m_world = world; - PhysicsScene = m_world.physicsScene; - } + private static string LogHeader = "[BULLETSIM CONSTRAINT]"; - public virtual void Dispose() - { - if (m_enabled) + protected BulletWorld m_world; + protected BSScene PhysicsScene; + protected BulletBody m_body1; + protected BulletBody m_body2; + protected BulletConstraint m_constraint; + protected bool m_enabled = false; + + public BulletBody Body1 { get { return m_body1; } } + public BulletBody Body2 { get { return m_body2; } } + public BulletConstraint Constraint { get { return m_constraint; } } + public abstract ConstraintType Type { get; } + public bool IsEnabled { get { return m_enabled; } } + + public BSConstraint(BulletWorld world) { - m_enabled = false; - if (m_constraint.HasPhysicalConstraint) + m_world = world; + PhysicsScene = m_world.physicsScene; + } + + public virtual void Dispose() + { + if (m_enabled) { - bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint); - m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", - m_body1.ID, - m_body1.ID, m_body1.AddrString, - m_body2.ID, m_body2.AddrString, - success); - m_constraint.Clear(); + m_enabled = false; + if (m_constraint.HasPhysicalConstraint) + { + bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint); + m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", + m_body1.ID, + m_body1.ID, m_body1.AddrString, + m_body2.ID, m_body2.AddrString, + success); + m_constraint.Clear(); + } } } - } - public virtual bool SetLinearLimits(Vector3 low, Vector3 high) - { - bool ret = false; - if (m_enabled) + public virtual bool SetLinearLimits(Vector3 low, Vector3 high) { - m_world.physicsScene.DetailLog("{0},BSConstraint.SetLinearLimits,taint,low={1},high={2}", m_body1.ID, low, high); - ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high); - } - return ret; - } - - public virtual bool SetAngularLimits(Vector3 low, Vector3 high) - { - bool ret = false; - if (m_enabled) - { - m_world.physicsScene.DetailLog("{0},BSConstraint.SetAngularLimits,taint,low={1},high={2}", m_body1.ID, low, high); - ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); - } - return ret; - } - - public virtual bool SetSolverIterations(float cnt) - { - bool ret = false; - if (m_enabled) - { - PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt); - ret = true; - } - return ret; - } - - public virtual bool CalculateTransforms() - { - bool ret = false; - if (m_enabled) - { - // Recompute the internal transforms - PhysicsScene.PE.CalculateTransforms(m_constraint); - ret = true; - } - return ret; - } - - // Reset this constraint making sure it has all its internal structures - // recomputed and is enabled and ready to go. - public virtual bool RecomputeConstraintVariables(float mass) - { - bool ret = false; - if (m_enabled) - { - ret = CalculateTransforms(); - if (ret) + bool ret = false; + if (m_enabled) { - // Setting an object's mass to zero (making it static like when it's selected) - // automatically disables the constraints. - // If the link is enabled, be sure to set the constraint itself to enabled. - PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true)); - } - else - { - m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID); + m_world.physicsScene.DetailLog("{0},BSConstraint.SetLinearLimits,taint,low={1},high={2}", m_body1.ID, low, high); + ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high); } + return ret; + } + + public virtual bool SetAngularLimits(Vector3 low, Vector3 high) + { + bool ret = false; + if (m_enabled) + { + m_world.physicsScene.DetailLog("{0},BSConstraint.SetAngularLimits,taint,low={1},high={2}", m_body1.ID, low, high); + ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high); + } + return ret; + } + + public virtual bool SetSolverIterations(float cnt) + { + bool ret = false; + if (m_enabled) + { + PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt); + ret = true; + } + return ret; + } + + public virtual bool CalculateTransforms() + { + bool ret = false; + if (m_enabled) + { + // Recompute the internal transforms + PhysicsScene.PE.CalculateTransforms(m_constraint); + ret = true; + } + return ret; + } + + // Reset this constraint making sure it has all its internal structures + // recomputed and is enabled and ready to go. + public virtual bool RecomputeConstraintVariables(float mass) + { + bool ret = false; + if (m_enabled) + { + ret = CalculateTransforms(); + if (ret) + { + // Setting an object's mass to zero (making it static like when it's selected) + // automatically disables the constraints. + // If the link is enabled, be sure to set the constraint itself to enabled. + PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true)); + } + else + { + m_world.physicsScene.Logger.ErrorFormat("{0} CalculateTransforms failed. A={1}, B={2}", LogHeader, Body1.ID, Body2.ID); + } + } + return ret; } - return ret; } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs index 4bcde2bb27..c1603b0a42 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraint6Dof.cs @@ -31,150 +31,149 @@ using OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { - -public class BSConstraint6Dof : BSConstraint -{ - private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; - - public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } - - public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2) :base(world) + public class BSConstraint6Dof : BSConstraint { - m_body1 = obj1; - m_body2 = obj2; - m_enabled = false; - } + private static string LogHeader = "[BULLETSIM 6DOF CONSTRAINT]"; - // Create a btGeneric6DofConstraint - public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frame1, Quaternion frame1rot, - Vector3 frame2, Quaternion frame2rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) - : base(world) - { - m_body1 = obj1; - m_body2 = obj2; - m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2, - frame1, frame1rot, - frame2, frame2rot, - useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); - m_enabled = true; - PhysicsScene.DetailLog("{0},BS6DofConstraint,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", - m_body1.ID, world.worldID, - obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); - PhysicsScene.DetailLog("{0},BS6DofConstraint,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}", - m_body1.ID, frame1, frame1rot, frame2, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); - } + public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } - // 6 Dof constraint based on a midpoint between the two constrained bodies - public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 joinPoint, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) - : base(world) - { - m_body1 = obj1; - m_body2 = obj2; - if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody) + public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2) :base(world) { - world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", - BSScene.DetailLogZero, world.worldID, - obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); - world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", - LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + m_body1 = obj1; + m_body2 = obj2; m_enabled = false; } - else + + // Create a btGeneric6DofConstraint + public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1, Quaternion frame1rot, + Vector3 frame2, Quaternion frame2rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + : base(world) { - m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2, - joinPoint, + m_body1 = obj1; + m_body2 = obj2; + m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2, + frame1, frame1rot, + frame2, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); - - PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", - m_body1.ID, world.worldID, m_constraint.AddrString, + m_enabled = true; + PhysicsScene.DetailLog("{0},BS6DofConstraint,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", + m_body1.ID, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + PhysicsScene.DetailLog("{0},BS6DofConstraint,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}", + m_body1.ID, frame1, frame1rot, frame2, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + } - if (!m_constraint.HasPhysicalConstraint) + // 6 Dof constraint based on a midpoint between the two constrained bodies + public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 joinPoint, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + : base(world) + { + m_body1 = obj1; + m_body2 = obj2; + if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody) { - world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", - LogHeader, obj1.ID, obj2.ID); + world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", + BSScene.DetailLogZero, world.worldID, + obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", + LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); m_enabled = false; } else { - m_enabled = true; + m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2, + joinPoint, + useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + + PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", + m_body1.ID, world.worldID, m_constraint.AddrString, + obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + + if (!m_constraint.HasPhysicalConstraint) + { + world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", + LogHeader, obj1.ID, obj2.ID); + m_enabled = false; + } + else + { + m_enabled = true; + } } } - } - // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object - public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot, - bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies) - : base(world) - { - m_body1 = obj1; - m_body2 = obj1; // Look out for confusion down the road - m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1, - frameInBloc, frameInBrot, - useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); - m_enabled = true; - PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", - m_body1.ID, world.worldID, obj1.ID, obj1.AddrString); - PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed, fBLoc={1},fBRot={2},usefA={3},disCol={4}", - m_body1.ID, frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); - } - - public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) - { - bool ret = false; - if (m_enabled) + // A 6 Dof constraint that is fixed in the world and constrained to a on-the-fly created static object + public BSConstraint6Dof(BulletWorld world, BulletBody obj1, Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameB, bool disableCollisionsBetweenLinkedBodies) + : base(world) { - PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot); - ret = true; + m_body1 = obj1; + m_body2 = obj1; // Look out for confusion down the road + m_constraint = PhysicsScene.PE.Create6DofConstraintFixed(m_world, m_body1, + frameInBloc, frameInBrot, + useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); + m_enabled = true; + PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed,wID={1},rID={2},rBody={3}", + m_body1.ID, world.worldID, obj1.ID, obj1.AddrString); + PhysicsScene.DetailLog("{0},BS6DofConstraint,createFixed, fBLoc={1},fBRot={2},usefA={3},disCol={4}", + m_body1.ID, frameInBloc, frameInBrot, useLinearReferenceFrameB, disableCollisionsBetweenLinkedBodies); } - return ret; - } - public bool SetCFMAndERP(float cfm, float erp) - { - bool ret = false; - if (m_enabled) + public bool SetFrames(Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot) { - PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); - PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); - PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); - ret = true; + bool ret = false; + if (m_enabled) + { + PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot); + ret = true; + } + return ret; } - return ret; - } - public bool UseFrameOffset(bool useOffset) - { - bool ret = false; - float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; - if (m_enabled) - ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff); - return ret; - } - - public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce) - { - bool ret = false; - float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; - if (m_enabled) + public bool SetCFMAndERP(float cfm, float erp) { - ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce); - m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", - BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); + bool ret = false; + if (m_enabled) + { + PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); + PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); + PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); + ret = true; + } + return ret; } - return ret; - } - public bool SetBreakingImpulseThreshold(float threshold) - { - bool ret = false; - if (m_enabled) - ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold); - return ret; + public bool UseFrameOffset(bool useOffset) + { + bool ret = false; + float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; + if (m_enabled) + ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff); + return ret; + } + + public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce) + { + bool ret = false; + float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; + if (m_enabled) + { + ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce); + m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", + BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); + } + return ret; + } + + public bool SetBreakingImpulseThreshold(float threshold) + { + bool ret = false; + if (m_enabled) + ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold); + return ret; + } } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs index 5746ac1746..479cc0ff72 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintCollection.cs @@ -32,150 +32,149 @@ using OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { - -public sealed class BSConstraintCollection : IDisposable -{ - // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); - // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]"; - - delegate bool ConstraintAction(BSConstraint constrain); - - private List m_constraints; - private BulletWorld m_world; - - public BSConstraintCollection(BulletWorld world) + public sealed class BSConstraintCollection : IDisposable { - m_world = world; - m_constraints = new List(); - } + // private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + // private static readonly string LogHeader = "[CONSTRAINT COLLECTION]"; - public void Dispose() - { - this.Clear(); - } + delegate bool ConstraintAction(BSConstraint constrain); - public void Clear() - { - lock (m_constraints) + private List m_constraints; + private BulletWorld m_world; + + public BSConstraintCollection(BulletWorld world) { - foreach (BSConstraint cons in m_constraints) - { - cons.Dispose(); - } - m_constraints.Clear(); - } - } - - public bool AddConstraint(BSConstraint cons) - { - lock (m_constraints) - { - // There is only one constraint between any bodies. Remove any old just to make sure. - RemoveAndDestroyConstraint(cons.Body1, cons.Body2); - - m_constraints.Add(cons); + m_world = world; + m_constraints = new List(); } - return true; - } - - // Get the constraint between two bodies. There can be only one. - // Return 'true' if a constraint was found. - public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint) - { - bool found = false; - BSConstraint foundConstraint = null; - - uint lookingID1 = body1.ID; - uint lookingID2 = body2.ID; - lock (m_constraints) + public void Dispose() { - foreach (BSConstraint constrain in m_constraints) + this.Clear(); + } + + public void Clear() + { + lock (m_constraints) { - if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2) - || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1)) + foreach (BSConstraint cons in m_constraints) { - foundConstraint = constrain; - found = true; - break; + cons.Dispose(); + } + m_constraints.Clear(); + } + } + + public bool AddConstraint(BSConstraint cons) + { + lock (m_constraints) + { + // There is only one constraint between any bodies. Remove any old just to make sure. + RemoveAndDestroyConstraint(cons.Body1, cons.Body2); + + m_constraints.Add(cons); + } + + return true; + } + + // Get the constraint between two bodies. There can be only one. + // Return 'true' if a constraint was found. + public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint) + { + bool found = false; + BSConstraint foundConstraint = null; + + uint lookingID1 = body1.ID; + uint lookingID2 = body2.ID; + lock (m_constraints) + { + foreach (BSConstraint constrain in m_constraints) + { + if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2) + || (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1)) + { + foundConstraint = constrain; + found = true; + break; + } } } + returnConstraint = foundConstraint; + return found; } - returnConstraint = foundConstraint; - return found; - } - // Remove any constraint between the passed bodies. - // Presumed there is only one such constraint possible. - // Return 'true' if a constraint was found and destroyed. - public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2) - { - bool ret = false; - lock (m_constraints) + // Remove any constraint between the passed bodies. + // Presumed there is only one such constraint possible. + // Return 'true' if a constraint was found and destroyed. + public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2) { - BSConstraint constrain; - if (this.TryGetConstraint(body1, body2, out constrain)) + bool ret = false; + lock (m_constraints) + { + BSConstraint constrain; + if (this.TryGetConstraint(body1, body2, out constrain)) + { + // remove the constraint from our collection + ret = RemoveAndDestroyConstraint(constrain); + } + } + + return ret; + } + + // The constraint MUST exist in the collection + // Could be called if the constraint was previously removed. + // Return 'true' if the constraint was actually removed and disposed. + public bool RemoveAndDestroyConstraint(BSConstraint constrain) + { + bool removed = false; + lock (m_constraints) { // remove the constraint from our collection - ret = RemoveAndDestroyConstraint(constrain); + removed = m_constraints.Remove(constrain); } + // Dispose() is safe to call multiple times + constrain.Dispose(); + return removed; } - return ret; - } - - // The constraint MUST exist in the collection - // Could be called if the constraint was previously removed. - // Return 'true' if the constraint was actually removed and disposed. - public bool RemoveAndDestroyConstraint(BSConstraint constrain) - { - bool removed = false; - lock (m_constraints) + // Remove all constraints that reference the passed body. + // Return 'true' if any constraints were destroyed. + public bool RemoveAndDestroyConstraint(BulletBody body1) { - // remove the constraint from our collection - removed = m_constraints.Remove(constrain); - } - // Dispose() is safe to call multiple times - constrain.Dispose(); - return removed; - } - - // Remove all constraints that reference the passed body. - // Return 'true' if any constraints were destroyed. - public bool RemoveAndDestroyConstraint(BulletBody body1) - { - List toRemove = new List(); - uint lookingID = body1.ID; - lock (m_constraints) - { - foreach (BSConstraint constrain in m_constraints) + List toRemove = new List(); + uint lookingID = body1.ID; + lock (m_constraints) { - if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID) + foreach (BSConstraint constrain in m_constraints) { - toRemove.Add(constrain); + if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID) + { + toRemove.Add(constrain); + } + } + foreach (BSConstraint constrain in toRemove) + { + m_constraints.Remove(constrain); + constrain.Dispose(); } } - foreach (BSConstraint constrain in toRemove) - { - m_constraints.Remove(constrain); - constrain.Dispose(); - } + return (toRemove.Count > 0); } - return (toRemove.Count > 0); - } - public bool RecalculateAllConstraints() - { - bool ret = false; - lock (m_constraints) + public bool RecalculateAllConstraints() { - foreach (BSConstraint constrain in m_constraints) + bool ret = false; + lock (m_constraints) { - constrain.CalculateTransforms(); - ret = true; + foreach (BSConstraint constrain in m_constraints) + { + constrain.CalculateTransforms(); + ret = true; + } } + return ret; } - return ret; } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs index e7566a83dd..dbfb572a74 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintConeTwist.cs @@ -31,24 +31,22 @@ using OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { - -public sealed class BSConstraintConeTwist : BSConstraint -{ - public override ConstraintType Type { get { return ConstraintType.CONETWIST_CONSTRAINT_TYPE; } } - - public BSConstraintConeTwist(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frameInAloc, Quaternion frameInArot, - Vector3 frameInBloc, Quaternion frameInBrot, - bool disableCollisionsBetweenLinkedBodies) - : base(world) + public sealed class BSConstraintConeTwist : BSConstraint { - m_body1 = obj1; - m_body2 = obj2; - m_constraint = PhysicsScene.PE.CreateConeTwistConstraint(world, obj1, obj2, - frameInAloc, frameInArot, frameInBloc, frameInBrot, - disableCollisionsBetweenLinkedBodies); - m_enabled = true; + public override ConstraintType Type { get { return ConstraintType.CONETWIST_CONSTRAINT_TYPE; } } + + public BSConstraintConeTwist(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool disableCollisionsBetweenLinkedBodies) + : base(world) + { + m_body1 = obj1; + m_body2 = obj2; + m_constraint = PhysicsScene.PE.CreateConeTwistConstraint(world, obj1, obj2, + frameInAloc, frameInArot, frameInBloc, frameInBrot, + disableCollisionsBetweenLinkedBodies); + m_enabled = true; + } } } - -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs index 83d42af912..40f67b9863 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSlider.cs @@ -31,25 +31,22 @@ using OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { - -public sealed class BSConstraintSlider : BSConstraint -{ - public override ConstraintType Type { get { return ConstraintType.SLIDER_CONSTRAINT_TYPE; } } - - public BSConstraintSlider(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frameInAloc, Quaternion frameInArot, - Vector3 frameInBloc, Quaternion frameInBrot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) - : base(world) + public sealed class BSConstraintSlider : BSConstraint { - m_body1 = obj1; - m_body2 = obj2; - m_constraint = PhysicsScene.PE.CreateSliderConstraint(world, obj1, obj2, - frameInAloc, frameInArot, frameInBloc, frameInBrot, - useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); - m_enabled = true; + public override ConstraintType Type { get { return ConstraintType.SLIDER_CONSTRAINT_TYPE; } } + + public BSConstraintSlider(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frameInAloc, Quaternion frameInArot, + Vector3 frameInBloc, Quaternion frameInBrot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + : base(world) + { + m_body1 = obj1; + m_body2 = obj2; + m_constraint = PhysicsScene.PE.CreateSliderConstraint(world, obj1, obj2, + frameInAloc, frameInArot, frameInBloc, frameInBrot, + useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + m_enabled = true; + } } - -} - } diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs index 563a1b1ef5..ed6c146728 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSConstraintSpring.cs @@ -31,73 +31,70 @@ using OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { - -public sealed class BSConstraintSpring : BSConstraint6Dof -{ - public override ConstraintType Type { get { return ConstraintType.D6_SPRING_CONSTRAINT_TYPE; } } - - public BSConstraintSpring(BulletWorld world, BulletBody obj1, BulletBody obj2, - Vector3 frame1Loc, Quaternion frame1Rot, - Vector3 frame2Loc, Quaternion frame2Rot, - bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) - :base(world, obj1, obj2) + public sealed class BSConstraintSpring : BSConstraint6Dof { - m_constraint = PhysicsScene.PE.Create6DofSpringConstraint(world, obj1, obj2, - frame1Loc, frame1Rot, frame2Loc, frame2Rot, - useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); - m_enabled = true; + public override ConstraintType Type { get { return ConstraintType.D6_SPRING_CONSTRAINT_TYPE; } } - PhysicsScene.DetailLog("{0},BSConstraintSpring,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", - obj1.ID, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); - PhysicsScene.DetailLog("{0},BSConstraintSpring,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}", - m_body1.ID, frame1Loc, frame1Rot, frame2Loc, frame2Rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + public BSConstraintSpring(BulletWorld world, BulletBody obj1, BulletBody obj2, + Vector3 frame1Loc, Quaternion frame1Rot, + Vector3 frame2Loc, Quaternion frame2Rot, + bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) + :base(world, obj1, obj2) + { + m_constraint = PhysicsScene.PE.Create6DofSpringConstraint(world, obj1, obj2, + frame1Loc, frame1Rot, frame2Loc, frame2Rot, + useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + m_enabled = true; + + PhysicsScene.DetailLog("{0},BSConstraintSpring,create,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", + obj1.ID, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString); + PhysicsScene.DetailLog("{0},BSConstraintSpring,create, f1Loc={1},f1Rot={2},f2Loc={3},f2Rot={4},usefA={5},disCol={6}", + m_body1.ID, frame1Loc, frame1Rot, frame2Loc, frame2Rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies); + } + + public bool SetAxisEnable(int pIndex, bool pAxisEnable) + { + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEnable,obj1ID={1},obj2ID={2},indx={3},enable={4}", + m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pAxisEnable); + PhysicsScene.PE.SpringEnable(m_constraint, pIndex, BSParam.NumericBool(pAxisEnable)); + return true; + } + + public bool SetStiffness(int pIndex, float pStiffness) + { + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetStiffness,obj1ID={1},obj2ID={2},indx={3},stiff={4}", + m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pStiffness); + PhysicsScene.PE.SpringSetStiffness(m_constraint, pIndex, pStiffness); + return true; + } + + public bool SetDamping(int pIndex, float pDamping) + { + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetDamping,obj1ID={1},obj2ID={2},indx={3},damp={4}", + m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pDamping); + PhysicsScene.PE.SpringSetDamping(m_constraint, pIndex, pDamping); + return true; + } + + public bool SetEquilibriumPoint(int pIndex, float pEqPoint) + { + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},indx={3},eqPoint={4}", + m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pEqPoint); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, pIndex, pEqPoint); + return true; + } + + public bool SetEquilibriumPoint(Vector3 linearEq, Vector3 angularEq) + { + PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},linearEq={3},angularEq={4}", + m_body1.ID, m_body1.ID, m_body2.ID, linearEq, angularEq); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 0, linearEq.X); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 1, linearEq.Y); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 2, linearEq.Z); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 3, angularEq.X); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 4, angularEq.Y); + PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 5, angularEq.Z); + return true; + } } - - public bool SetAxisEnable(int pIndex, bool pAxisEnable) - { - PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEnable,obj1ID={1},obj2ID={2},indx={3},enable={4}", - m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pAxisEnable); - PhysicsScene.PE.SpringEnable(m_constraint, pIndex, BSParam.NumericBool(pAxisEnable)); - return true; - } - - public bool SetStiffness(int pIndex, float pStiffness) - { - PhysicsScene.DetailLog("{0},BSConstraintSpring.SetStiffness,obj1ID={1},obj2ID={2},indx={3},stiff={4}", - m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pStiffness); - PhysicsScene.PE.SpringSetStiffness(m_constraint, pIndex, pStiffness); - return true; - } - - public bool SetDamping(int pIndex, float pDamping) - { - PhysicsScene.DetailLog("{0},BSConstraintSpring.SetDamping,obj1ID={1},obj2ID={2},indx={3},damp={4}", - m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pDamping); - PhysicsScene.PE.SpringSetDamping(m_constraint, pIndex, pDamping); - return true; - } - - public bool SetEquilibriumPoint(int pIndex, float pEqPoint) - { - PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},indx={3},eqPoint={4}", - m_body1.ID, m_body1.ID, m_body2.ID, pIndex, pEqPoint); - PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, pIndex, pEqPoint); - return true; - } - - public bool SetEquilibriumPoint(Vector3 linearEq, Vector3 angularEq) - { - PhysicsScene.DetailLog("{0},BSConstraintSpring.SetEquilibriumPoint,obj1ID={1},obj2ID={2},linearEq={3},angularEq={4}", - m_body1.ID, m_body1.ID, m_body2.ID, linearEq, angularEq); - PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 0, linearEq.X); - PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 1, linearEq.Y); - PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 2, linearEq.Z); - PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 3, angularEq.X); - PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 4, angularEq.Y); - PhysicsScene.PE.SpringSetEquilibriumPoint(m_constraint, 5, angularEq.Z); - return true; - } - -} - } \ No newline at end of file diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs index 13c1361f73..ea87f7dc48 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinkset.cs @@ -32,472 +32,471 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { - -public abstract class BSLinkset -{ - // private static string LogHeader = "[BULLETSIM LINKSET]"; - - public enum LinksetImplementation + public abstract class BSLinkset { - Constraint = 0, // linkset tied together with constraints - Compound = 1, // linkset tied together as a compound object - Manual = 2 // linkset tied together manually (code moves all the pieces) - } - // Create the correct type of linkset for this child - public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent) - { - BSLinkset ret = null; + // private static string LogHeader = "[BULLETSIM LINKSET]"; - switch (parent.LinksetType) + public enum LinksetImplementation { - case LinksetImplementation.Constraint: - ret = new BSLinksetConstraints(physScene, parent); - break; - case LinksetImplementation.Compound: - ret = new BSLinksetCompound(physScene, parent); - break; - case LinksetImplementation.Manual: - // ret = new BSLinksetManual(physScene, parent); - break; - default: - ret = new BSLinksetCompound(physScene, parent); - break; + Constraint = 0, // linkset tied together with constraints + Compound = 1, // linkset tied together as a compound object + Manual = 2 // linkset tied together manually (code moves all the pieces) } - if (ret == null) + // Create the correct type of linkset for this child + public static BSLinkset Factory(BSScene physScene, BSPrimLinkable parent) { - physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID); - } - return ret; - } + BSLinkset ret = null; - public class BSLinkInfo - { - public BSPrimLinkable member; - public BSLinkInfo(BSPrimLinkable pMember) - { - member = pMember; - } - public virtual void ResetLink() { } - public virtual void SetLinkParameters(BSConstraint constrain) { } - // Returns 'true' if physical property updates from the child should be reported to the simulator - public virtual bool ShouldUpdateChildProperties() { return false; } - } - - public LinksetImplementation LinksetImpl { get; protected set; } - - public BSPrimLinkable LinksetRoot { get; protected set; } - - protected BSScene m_physicsScene { get; private set; } - - static int m_nextLinksetID = 1; - public int LinksetID { get; private set; } - - // The children under the root in this linkset. - // protected HashSet m_children; - protected Dictionary m_children; - - // We lock the diddling of linkset classes to prevent any badness. - // This locks the modification of the instances of this class. Changes - // to the physical representation is done via the tainting mechenism. - protected object m_linksetActivityLock = new Object(); - - // We keep the prim's mass in the linkset structure since it could be dependent on other prims - public float LinksetMass { get; protected set; } - - public virtual bool LinksetIsColliding { get { return false; } } - - public OMV.Vector3 CenterOfMass - { - get { return ComputeLinksetCenterOfMass(); } - } - - public OMV.Vector3 GeometricCenter - { - get { return ComputeLinksetGeometricCenter(); } - } - - protected BSLinkset(BSScene scene, BSPrimLinkable parent) - { - // A simple linkset of one (no children) - LinksetID = m_nextLinksetID++; - // We create LOTS of linksets. - if (m_nextLinksetID <= 0) - m_nextLinksetID = 1; - m_physicsScene = scene; - LinksetRoot = parent; - m_children = new Dictionary(); - LinksetMass = parent.RawMass; - Rebuilding = false; - RebuildScheduled = false; - - parent.ClearDisplacement(); - } - - // Link to a linkset where the child knows the parent. - // Parent changing should not happen so do some sanity checking. - // We return the parent's linkset so the child can track its membership. - // Called at runtime. - public BSLinkset AddMeToLinkset(BSPrimLinkable child) - { - lock (m_linksetActivityLock) - { - // Don't add the root to its own linkset - if (!IsRoot(child)) - AddChildToLinkset(child); - LinksetMass = ComputeLinksetMass(); - } - return this; - } - - // Remove a child from a linkset. - // Returns a new linkset for the child which is a linkset of one (just the - // orphened child). - // Called at runtime. - public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime) - { - lock (m_linksetActivityLock) - { - if (IsRoot(child)) + switch (parent.LinksetType) { - // Cannot remove the root from a linkset. - return this; - } - RemoveChildFromLinkset(child, inTaintTime); - LinksetMass = ComputeLinksetMass(); - } - - // The child is down to a linkset of just itself - return BSLinkset.Factory(m_physicsScene, child); - } - - // Return 'true' if the passed object is the root object of this linkset - public bool IsRoot(BSPrimLinkable requestor) - { - return (requestor.LocalID == LinksetRoot.LocalID); - } - - public int NumberOfChildren { get { return m_children.Count; } } - - // Return 'true' if this linkset has any children (more than the root member) - public bool HasAnyChildren { get { return (m_children.Count > 0); } } - - // Return 'true' if this child is in this linkset - public bool HasChild(BSPrimLinkable child) - { - bool ret = false; - lock (m_linksetActivityLock) - { - ret = m_children.ContainsKey(child); - } - return ret; - } - - // Perform an action on each member of the linkset including root prim. - // Depends on the action on whether this should be done at taint time. - public delegate bool ForEachMemberAction(BSPrimLinkable obj); - public virtual bool ForEachMember(ForEachMemberAction action) - { - bool ret = false; - lock (m_linksetActivityLock) - { - action(LinksetRoot); - foreach (BSPrimLinkable po in m_children.Keys) - { - if (action(po)) + case LinksetImplementation.Constraint: + ret = new BSLinksetConstraints(physScene, parent); + break; + case LinksetImplementation.Compound: + ret = new BSLinksetCompound(physScene, parent); + break; + case LinksetImplementation.Manual: + // ret = new BSLinksetManual(physScene, parent); + break; + default: + ret = new BSLinksetCompound(physScene, parent); break; } - } - return ret; - } - - public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo) - { - bool ret = false; - BSLinkInfo found = null; - lock (m_linksetActivityLock) - { - ret = m_children.TryGetValue(child, out found); - } - foundInfo = found; - return ret; - } - // Perform an action on each member of the linkset including root prim. - // Depends on the action on whether this should be done at taint time. - public delegate bool ForEachLinkInfoAction(BSLinkInfo obj); - public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action) - { - bool ret = false; - lock (m_linksetActivityLock) - { - foreach (BSLinkInfo po in m_children.Values) + if (ret == null) { - if (action(po)) - break; + physScene.Logger.ErrorFormat("[BULLETSIM LINKSET] Factory could not create linkset. Parent name={1}, ID={2}", parent.Name, parent.LocalID); } - } - return ret; - } - - // Check the type of the link and return 'true' if the link is flexible and the - // updates from the child should be sent to the simulator so things change. - public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child) - { - bool ret = false; - - BSLinkInfo linkInfo; - if (m_children.TryGetValue(child, out linkInfo)) - { - ret = linkInfo.ShouldUpdateChildProperties(); - } - - return ret; - } - - // Called after a simulation step to post a collision with this object. - // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have - // anything to add for the collision and it should be passed through normal processing. - // Default processing for a linkset. - public virtual bool HandleCollide(BSPhysObject collider, BSPhysObject collidee, - OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) - { - bool ret = false; - - // prims in the same linkset cannot collide with each other - BSPrimLinkable convCollidee = collidee as BSPrimLinkable; - if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID)) - { - // By returning 'true', we tell the caller the collision has been 'handled' so it won't - // do anything about this collision and thus, effectivily, ignoring the collision. - ret = true; - } - else - { - // Not a collision between members of the linkset. Must be a real collision. - // So the linkset root can know if there is a collision anywhere in the linkset. - LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep; - } - - return ret; - } - - // I am the root of a linkset and a new child is being added - // Called while LinkActivity is locked. - protected abstract void AddChildToLinkset(BSPrimLinkable child); - - // I am the root of a linkset and one of my children is being removed. - // Safe to call even if the child is not really in my linkset. - protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime); - - // When physical properties are changed the linkset needs to recalculate - // its internal properties. - // May be called at runtime or taint-time. - public virtual void Refresh(BSPrimLinkable requestor) - { - LinksetMass = ComputeLinksetMass(); - } - - // Flag denoting the linkset is in the process of being rebuilt. - // Used to know not the schedule a rebuild in the middle of a rebuild. - // Because of potential update calls that could want to schedule another rebuild. - protected bool Rebuilding { get; set; } - - // Flag saying a linkset rebuild has been scheduled. - // This is turned on when the rebuild is requested and turned off when - // the rebuild is complete. Used to limit modifications to the - // linkset parameters while the linkset is in an intermediate state. - // Protected by a "lock(m_linsetActivityLock)" on the BSLinkset object - public bool RebuildScheduled { get; protected set; } - - // The object is going dynamic (physical). Do any setup necessary - // for a dynamic linkset. - // Only the state of the passed object can be modified. The rest of the linkset - // has not yet been fully constructed. - // Return 'true' if any properties updated on the passed object. - // Called at taint-time! - public abstract bool MakeDynamic(BSPrimLinkable child); - - public virtual bool AllPartsComplete - { - get { - bool ret = true; - this.ForEachMember((member) => - { - if ((!member.IsInitialized) || member.IsIncomplete || member.PrimAssetState == BSPhysObject.PrimAssetCondition.Waiting) - { - ret = false; - return true; // exit loop - } - return false; // continue loop - }); return ret; } - } - // The object is going static (non-physical). Do any setup necessary - // for a static linkset. - // Return 'true' if any properties updated on the passed object. - // Called at taint-time! - public abstract bool MakeStatic(BSPrimLinkable child); + public class BSLinkInfo + { + public BSPrimLinkable member; + public BSLinkInfo(BSPrimLinkable pMember) + { + member = pMember; + } + public virtual void ResetLink() { } + public virtual void SetLinkParameters(BSConstraint constrain) { } + // Returns 'true' if physical property updates from the child should be reported to the simulator + public virtual bool ShouldUpdateChildProperties() { return false; } + } - // Called when a parameter update comes from the physics engine for any object - // of the linkset is received. - // Passed flag is update came from physics engine (true) or the user (false). - // Called at taint-time!! - public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject); + public LinksetImplementation LinksetImpl { get; protected set; } - // Routine used when rebuilding the body of the root of the linkset - // Destroy all the constraints have have been made to root. - // This is called when the root body is changing. - // Returns 'true' of something was actually removed and would need restoring - // Called at taint-time!! - public abstract bool RemoveDependencies(BSPrimLinkable child); + public BSPrimLinkable LinksetRoot { get; protected set; } - // ================================================================ - // Some physical setting happen to all members of the linkset - public virtual void SetPhysicalFriction(float friction) - { - ForEachMember((member) => - { - if (member.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetFriction(member.PhysBody, friction); - return false; // 'false' says to continue looping - } - ); - } - public virtual void SetPhysicalRestitution(float restitution) - { - ForEachMember((member) => - { - if (member.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetRestitution(member.PhysBody, restitution); - return false; // 'false' says to continue looping - } - ); - } - public virtual void SetPhysicalGravity(OMV.Vector3 gravity) - { - ForEachMember((member) => - { - if (member.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetGravity(member.PhysBody, gravity); - return false; // 'false' says to continue looping - } - ); - } - public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) - { - ForEachMember((member) => - { - if (member.PhysBody.HasPhysicalBody) - { - OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass); - member.Inertia = inertia * inertiaFactor; - m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia); - m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); - DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia); + protected BSScene m_physicsScene { get; private set; } - } - return false; // 'false' says to continue looping - } - ); - } - public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags) - { - ForEachMember((member) => - { - if (member.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags); - return false; // 'false' says to continue looping - } - ); - } - public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags) - { - ForEachMember((member) => - { - if (member.PhysBody.HasPhysicalBody) - m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags); - return false; // 'false' says to continue looping - } - ); - } - public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) - { - ForEachMember((member) => - { - if (member.PhysBody.HasPhysicalBody) - m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags); - return false; // 'false' says to continue looping - } - ); - } - // ================================================================ - protected virtual float ComputeLinksetMass() - { - float mass = LinksetRoot.RawMass; - if (HasAnyChildren) + static int m_nextLinksetID = 1; + public int LinksetID { get; private set; } + + // The children under the root in this linkset. + // protected HashSet m_children; + protected Dictionary m_children; + + // We lock the diddling of linkset classes to prevent any badness. + // This locks the modification of the instances of this class. Changes + // to the physical representation is done via the tainting mechenism. + protected object m_linksetActivityLock = new Object(); + + // We keep the prim's mass in the linkset structure since it could be dependent on other prims + public float LinksetMass { get; protected set; } + + public virtual bool LinksetIsColliding { get { return false; } } + + public OMV.Vector3 CenterOfMass + { + get { return ComputeLinksetCenterOfMass(); } + } + + public OMV.Vector3 GeometricCenter + { + get { return ComputeLinksetGeometricCenter(); } + } + + protected BSLinkset(BSScene scene, BSPrimLinkable parent) + { + // A simple linkset of one (no children) + LinksetID = m_nextLinksetID++; + // We create LOTS of linksets. + if (m_nextLinksetID <= 0) + m_nextLinksetID = 1; + m_physicsScene = scene; + LinksetRoot = parent; + m_children = new Dictionary(); + LinksetMass = parent.RawMass; + Rebuilding = false; + RebuildScheduled = false; + + parent.ClearDisplacement(); + } + + // Link to a linkset where the child knows the parent. + // Parent changing should not happen so do some sanity checking. + // We return the parent's linkset so the child can track its membership. + // Called at runtime. + public BSLinkset AddMeToLinkset(BSPrimLinkable child) { lock (m_linksetActivityLock) { - foreach (BSPrimLinkable bp in m_children.Keys) + // Don't add the root to its own linkset + if (!IsRoot(child)) + AddChildToLinkset(child); + LinksetMass = ComputeLinksetMass(); + } + return this; + } + + // Remove a child from a linkset. + // Returns a new linkset for the child which is a linkset of one (just the + // orphened child). + // Called at runtime. + public BSLinkset RemoveMeFromLinkset(BSPrimLinkable child, bool inTaintTime) + { + lock (m_linksetActivityLock) + { + if (IsRoot(child)) { - mass += bp.RawMass; + // Cannot remove the root from a linkset. + return this; + } + RemoveChildFromLinkset(child, inTaintTime); + LinksetMass = ComputeLinksetMass(); + } + + // The child is down to a linkset of just itself + return BSLinkset.Factory(m_physicsScene, child); + } + + // Return 'true' if the passed object is the root object of this linkset + public bool IsRoot(BSPrimLinkable requestor) + { + return (requestor.LocalID == LinksetRoot.LocalID); + } + + public int NumberOfChildren { get { return m_children.Count; } } + + // Return 'true' if this linkset has any children (more than the root member) + public bool HasAnyChildren { get { return (m_children.Count > 0); } } + + // Return 'true' if this child is in this linkset + public bool HasChild(BSPrimLinkable child) + { + bool ret = false; + lock (m_linksetActivityLock) + { + ret = m_children.ContainsKey(child); + } + return ret; + } + + // Perform an action on each member of the linkset including root prim. + // Depends on the action on whether this should be done at taint time. + public delegate bool ForEachMemberAction(BSPrimLinkable obj); + public virtual bool ForEachMember(ForEachMemberAction action) + { + bool ret = false; + lock (m_linksetActivityLock) + { + action(LinksetRoot); + foreach (BSPrimLinkable po in m_children.Keys) + { + if (action(po)) + break; } } + return ret; } - return mass; - } - // Computes linkset's center of mass in world coordinates. - protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() - { - OMV.Vector3 com; - lock (m_linksetActivityLock) + public bool TryGetLinkInfo(BSPrimLinkable child, out BSLinkInfo foundInfo) { - com = LinksetRoot.Position * LinksetRoot.RawMass; - float totalMass = LinksetRoot.RawMass; - - foreach (BSPrimLinkable bp in m_children.Keys) + bool ret = false; + BSLinkInfo found = null; + lock (m_linksetActivityLock) { - com += bp.Position * bp.RawMass; - totalMass += bp.RawMass; + ret = m_children.TryGetValue(child, out found); } - if (totalMass != 0f) - com /= totalMass; + foundInfo = found; + return ret; } - - return com; - } - - protected virtual OMV.Vector3 ComputeLinksetGeometricCenter() - { - OMV.Vector3 com; - lock (m_linksetActivityLock) + // Perform an action on each member of the linkset including root prim. + // Depends on the action on whether this should be done at taint time. + public delegate bool ForEachLinkInfoAction(BSLinkInfo obj); + public virtual bool ForEachLinkInfo(ForEachLinkInfoAction action) { - com = LinksetRoot.Position; - - foreach (BSPrimLinkable bp in m_children.Keys) + bool ret = false; + lock (m_linksetActivityLock) { - com += bp.Position; + foreach (BSLinkInfo po in m_children.Values) + { + if (action(po)) + break; + } } - com /= (m_children.Count + 1); + return ret; } - return com; - } + // Check the type of the link and return 'true' if the link is flexible and the + // updates from the child should be sent to the simulator so things change. + public virtual bool ShouldReportPropertyUpdates(BSPrimLinkable child) + { + bool ret = false; - #region Extension - public virtual object Extension(string pFunct, params object[] pParams) - { - return null; - } - #endregion // Extension + BSLinkInfo linkInfo; + if (m_children.TryGetValue(child, out linkInfo)) + { + ret = linkInfo.ShouldUpdateChildProperties(); + } - // Invoke the detailed logger and output something if it's enabled. - protected void DetailLog(string msg, params Object[] args) - { - if (m_physicsScene.PhysicsLogging.Enabled) - m_physicsScene.DetailLog(msg, args); + return ret; + } + + // Called after a simulation step to post a collision with this object. + // Return 'true' if linkset processed the collision. 'false' says the linkset didn't have + // anything to add for the collision and it should be passed through normal processing. + // Default processing for a linkset. + public virtual bool HandleCollide(BSPhysObject collider, BSPhysObject collidee, + OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) + { + bool ret = false; + + // prims in the same linkset cannot collide with each other + BSPrimLinkable convCollidee = collidee as BSPrimLinkable; + if (convCollidee != null && (LinksetID == convCollidee.Linkset.LinksetID)) + { + // By returning 'true', we tell the caller the collision has been 'handled' so it won't + // do anything about this collision and thus, effectivily, ignoring the collision. + ret = true; + } + else + { + // Not a collision between members of the linkset. Must be a real collision. + // So the linkset root can know if there is a collision anywhere in the linkset. + LinksetRoot.SomeCollisionSimulationStep = m_physicsScene.SimulationStep; + } + + return ret; + } + + // I am the root of a linkset and a new child is being added + // Called while LinkActivity is locked. + protected abstract void AddChildToLinkset(BSPrimLinkable child); + + // I am the root of a linkset and one of my children is being removed. + // Safe to call even if the child is not really in my linkset. + protected abstract void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime); + + // When physical properties are changed the linkset needs to recalculate + // its internal properties. + // May be called at runtime or taint-time. + public virtual void Refresh(BSPrimLinkable requestor) + { + LinksetMass = ComputeLinksetMass(); + } + + // Flag denoting the linkset is in the process of being rebuilt. + // Used to know not the schedule a rebuild in the middle of a rebuild. + // Because of potential update calls that could want to schedule another rebuild. + protected bool Rebuilding { get; set; } + + // Flag saying a linkset rebuild has been scheduled. + // This is turned on when the rebuild is requested and turned off when + // the rebuild is complete. Used to limit modifications to the + // linkset parameters while the linkset is in an intermediate state. + // Protected by a "lock(m_linsetActivityLock)" on the BSLinkset object + public bool RebuildScheduled { get; protected set; } + + // The object is going dynamic (physical). Do any setup necessary + // for a dynamic linkset. + // Only the state of the passed object can be modified. The rest of the linkset + // has not yet been fully constructed. + // Return 'true' if any properties updated on the passed object. + // Called at taint-time! + public abstract bool MakeDynamic(BSPrimLinkable child); + + public virtual bool AllPartsComplete + { + get { + bool ret = true; + this.ForEachMember((member) => + { + if ((!member.IsInitialized) || member.IsIncomplete || member.PrimAssetState == BSPhysObject.PrimAssetCondition.Waiting) + { + ret = false; + return true; // exit loop + } + return false; // continue loop + }); + return ret; + } + } + + // The object is going static (non-physical). Do any setup necessary + // for a static linkset. + // Return 'true' if any properties updated on the passed object. + // Called at taint-time! + public abstract bool MakeStatic(BSPrimLinkable child); + + // Called when a parameter update comes from the physics engine for any object + // of the linkset is received. + // Passed flag is update came from physics engine (true) or the user (false). + // Called at taint-time!! + public abstract void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable physObject); + + // Routine used when rebuilding the body of the root of the linkset + // Destroy all the constraints have have been made to root. + // This is called when the root body is changing. + // Returns 'true' of something was actually removed and would need restoring + // Called at taint-time!! + public abstract bool RemoveDependencies(BSPrimLinkable child); + + // ================================================================ + // Some physical setting happen to all members of the linkset + public virtual void SetPhysicalFriction(float friction) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetFriction(member.PhysBody, friction); + return false; // 'false' says to continue looping + } + ); + } + public virtual void SetPhysicalRestitution(float restitution) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetRestitution(member.PhysBody, restitution); + return false; // 'false' says to continue looping + } + ); + } + public virtual void SetPhysicalGravity(OMV.Vector3 gravity) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetGravity(member.PhysBody, gravity); + return false; // 'false' says to continue looping + } + ); + } + public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + { + OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass); + member.Inertia = inertia * inertiaFactor; + m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia); + m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); + DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia); + + } + return false; // 'false' says to continue looping + } + ); + } + public virtual void SetPhysicalCollisionFlags(CollisionFlags collFlags) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetCollisionFlags(member.PhysBody, collFlags); + return false; // 'false' says to continue looping + } + ); + } + public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags); + return false; // 'false' says to continue looping + } + ); + } + public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) + { + ForEachMember((member) => + { + if (member.PhysBody.HasPhysicalBody) + m_physicsScene.PE.RemoveFromCollisionFlags(member.PhysBody, collFlags); + return false; // 'false' says to continue looping + } + ); + } + // ================================================================ + protected virtual float ComputeLinksetMass() + { + float mass = LinksetRoot.RawMass; + if (HasAnyChildren) + { + lock (m_linksetActivityLock) + { + foreach (BSPrimLinkable bp in m_children.Keys) + { + mass += bp.RawMass; + } + } + } + return mass; + } + + // Computes linkset's center of mass in world coordinates. + protected virtual OMV.Vector3 ComputeLinksetCenterOfMass() + { + OMV.Vector3 com; + lock (m_linksetActivityLock) + { + com = LinksetRoot.Position * LinksetRoot.RawMass; + float totalMass = LinksetRoot.RawMass; + + foreach (BSPrimLinkable bp in m_children.Keys) + { + com += bp.Position * bp.RawMass; + totalMass += bp.RawMass; + } + if (totalMass != 0f) + com /= totalMass; + } + + return com; + } + + protected virtual OMV.Vector3 ComputeLinksetGeometricCenter() + { + OMV.Vector3 com; + lock (m_linksetActivityLock) + { + com = LinksetRoot.Position; + + foreach (BSPrimLinkable bp in m_children.Keys) + { + com += bp.Position; + } + com /= (m_children.Count + 1); + } + + return com; + } + + #region Extension + public virtual object Extension(string pFunct, params object[] pParams) + { + return null; + } + #endregion // Extension + + // Invoke the detailed logger and output something if it's enabled. + protected void DetailLog(string msg, params Object[] args) + { + if (m_physicsScene.PhysicsLogging.Enabled) + m_physicsScene.DetailLog(msg, args); + } } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs index dc390b2e8d..924d1c8750 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetCompound.cs @@ -34,445 +34,444 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { - -public sealed class BSLinksetCompound : BSLinkset -{ + public sealed class BSLinksetCompound : BSLinkset + { #pragma warning disable 414 - private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; + private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; #pragma warning restore 414 - public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) - : base(scene, parent) - { - LinksetImpl = LinksetImplementation.Compound; - } - - // ================================================================ - // Changing the physical property of the linkset only needs to change the root - public override void SetPhysicalFriction(float friction) - { - if (LinksetRoot.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction); - } - public override void SetPhysicalRestitution(float restitution) - { - if (LinksetRoot.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution); - } - public override void SetPhysicalGravity(OMV.Vector3 gravity) - { - if (LinksetRoot.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity); - } - public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) - { - OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass); - LinksetRoot.Inertia = inertia * inertiaFactor; - m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia); - m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody); - } - public override void SetPhysicalCollisionFlags(CollisionFlags collFlags) - { - if (LinksetRoot.PhysBody.HasPhysicalBody) - m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags); - } - public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags) - { - if (LinksetRoot.PhysBody.HasPhysicalBody) - m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags); - } - public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) - { - if (LinksetRoot.PhysBody.HasPhysicalBody) - m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags); - } - // ================================================================ - - // When physical properties are changed the linkset needs to recalculate - // its internal properties. - public override void Refresh(BSPrimLinkable requestor) - { - // Something changed so do the rebuilding thing - ScheduleRebuild(requestor); - base.Refresh(requestor); - } - - // Schedule a refresh to happen after all the other taint processing. - private void ScheduleRebuild(BSPrimLinkable requestor) - { - // When rebuilding, it is possible to set properties that would normally require a rebuild. - // If already rebuilding, don't request another rebuild. - // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. - lock (m_linksetActivityLock) + public BSLinksetCompound(BSScene scene, BSPrimLinkable parent) + : base(scene, parent) { - if (!RebuildScheduled && !Rebuilding && HasAnyChildren) - { - InternalScheduleRebuild(requestor); - } + LinksetImpl = LinksetImplementation.Compound; } - } - - // Must be called with m_linksetActivityLock or race conditions will haunt you. - private void InternalScheduleRebuild(BSPrimLinkable requestor) - { - DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rebuilding={1},hasChildren={2}", - requestor.LocalID, Rebuilding, HasAnyChildren); - RebuildScheduled = true; - m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() + + // ================================================================ + // Changing the physical property of the linkset only needs to change the root + public override void SetPhysicalFriction(float friction) { - if (HasAnyChildren) + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetFriction(LinksetRoot.PhysBody, friction); + } + public override void SetPhysicalRestitution(float restitution) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetRestitution(LinksetRoot.PhysBody, restitution); + } + public override void SetPhysicalGravity(OMV.Vector3 gravity) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity); + } + public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass) + { + OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass); + LinksetRoot.Inertia = inertia * inertiaFactor; + m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia); + m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody); + } + public override void SetPhysicalCollisionFlags(CollisionFlags collFlags) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags); + } + public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags); + } + public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) + { + if (LinksetRoot.PhysBody.HasPhysicalBody) + m_physicsScene.PE.RemoveFromCollisionFlags(LinksetRoot.PhysBody, collFlags); + } + // ================================================================ + + // When physical properties are changed the linkset needs to recalculate + // its internal properties. + public override void Refresh(BSPrimLinkable requestor) + { + // Something changed so do the rebuilding thing + ScheduleRebuild(requestor); + base.Refresh(requestor); + } + + // Schedule a refresh to happen after all the other taint processing. + private void ScheduleRebuild(BSPrimLinkable requestor) + { + // When rebuilding, it is possible to set properties that would normally require a rebuild. + // If already rebuilding, don't request another rebuild. + // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. + lock (m_linksetActivityLock) { - if (this.AllPartsComplete) + if (!RebuildScheduled && !Rebuilding && HasAnyChildren) { - RecomputeLinksetCompound(); - } - else - { - DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rescheduling because not all children complete", - requestor.LocalID); InternalScheduleRebuild(requestor); } } - RebuildScheduled = false; - }); - } - - // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset. - // Only the state of the passed object can be modified. The rest of the linkset - // has not yet been fully constructed. - // Return 'true' if any properties updated on the passed object. - // Called at taint-time! - public override bool MakeDynamic(BSPrimLinkable child) - { - bool ret = false; - DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); - if (IsRoot(child)) - { - // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. - Refresh(LinksetRoot); } - return ret; - } - - // The object is going static (non-physical). We do not do anything for static linksets. - // Return 'true' if any properties updated on the passed object. - // Called at taint-time! - public override bool MakeStatic(BSPrimLinkable child) - { - bool ret = false; - - DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); - child.ClearDisplacement(); - if (IsRoot(child)) + + // Must be called with m_linksetActivityLock or race conditions will haunt you. + private void InternalScheduleRebuild(BSPrimLinkable requestor) { - // Schedule a rebuild to verify that the root shape is set to the real shape. - Refresh(LinksetRoot); - } - return ret; - } - - // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then. - // Called at taint-time. - public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) - { - if (!LinksetRoot.IsPhysicallyActive) - { - // No reason to do this physical stuff for static linksets. - DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID); - return; - } - - // The user moving a child around requires the rebuilding of the linkset compound shape - // One problem is this happens when a border is crossed -- the simulator implementation - // stores the position into the group which causes the move of the object - // but it also means all the child positions get updated. - // What would cause an unnecessary rebuild so we make sure the linkset is in a - // region before bothering to do a rebuild. - if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) - { - // If a child of the linkset is updating only the position or rotation, that can be done - // without rebuilding the linkset. - // If a handle for the child can be fetch, we update the child here. If a rebuild was - // scheduled by someone else, the rebuild will just replace this setting. - - bool updatedChild = false; - // Anything other than updating position or orientation usually means a physical update - // and that is caused by us updating the object. - if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) + DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rebuilding={1},hasChildren={2}", + requestor.LocalID, Rebuilding, HasAnyChildren); + RebuildScheduled = true; + m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() { - // Find the physical instance of the child - if (!RebuildScheduled // if rebuilding, let the rebuild do it - && !LinksetRoot.IsIncomplete // if waiting for assets or whatever, don't change - && LinksetRoot.PhysShape.HasPhysicalShape // there must be a physical shape assigned - && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) + if (HasAnyChildren) { - // It is possible that the linkset is still under construction and the child is not yet - // inserted into the compound shape. A rebuild of the linkset in a pre-step action will - // build the whole thing with the new position or rotation. - // The index must be checked because Bullet references the child array but does no validity - // checking of the child index passed. - int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); - if (updated.LinksetChildIndex < numLinksetChildren) + if (this.AllPartsComplete) { - BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); - if (linksetChildShape.HasPhysicalShape) + RecomputeLinksetCompound(); + } + else + { + DetailLog("{0},BSLinksetCompound.InternalScheduleRebuild,,rescheduling because not all children complete", + requestor.LocalID); + InternalScheduleRebuild(requestor); + } + } + RebuildScheduled = false; + }); + } + + // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset. + // Only the state of the passed object can be modified. The rest of the linkset + // has not yet been fully constructed. + // Return 'true' if any properties updated on the passed object. + // Called at taint-time! + public override bool MakeDynamic(BSPrimLinkable child) + { + bool ret = false; + DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); + if (IsRoot(child)) + { + // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. + Refresh(LinksetRoot); + } + return ret; + } + + // The object is going static (non-physical). We do not do anything for static linksets. + // Return 'true' if any properties updated on the passed object. + // Called at taint-time! + public override bool MakeStatic(BSPrimLinkable child) + { + bool ret = false; + + DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); + child.ClearDisplacement(); + if (IsRoot(child)) + { + // Schedule a rebuild to verify that the root shape is set to the real shape. + Refresh(LinksetRoot); + } + return ret; + } + + // 'physicalUpdate' is true if these changes came directly from the physics engine. Don't need to rebuild then. + // Called at taint-time. + public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable updated) + { + if (!LinksetRoot.IsPhysicallyActive) + { + // No reason to do this physical stuff for static linksets. + DetailLog("{0},BSLinksetCompound.UpdateProperties,notPhysical", LinksetRoot.LocalID); + return; + } + + // The user moving a child around requires the rebuilding of the linkset compound shape + // One problem is this happens when a border is crossed -- the simulator implementation + // stores the position into the group which causes the move of the object + // but it also means all the child positions get updated. + // What would cause an unnecessary rebuild so we make sure the linkset is in a + // region before bothering to do a rebuild. + if (!IsRoot(updated) && m_physicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) + { + // If a child of the linkset is updating only the position or rotation, that can be done + // without rebuilding the linkset. + // If a handle for the child can be fetch, we update the child here. If a rebuild was + // scheduled by someone else, the rebuild will just replace this setting. + + bool updatedChild = false; + // Anything other than updating position or orientation usually means a physical update + // and that is caused by us updating the object. + if ((whichUpdated & ~(UpdatedProperties.Position | UpdatedProperties.Orientation)) == 0) + { + // Find the physical instance of the child + if (!RebuildScheduled // if rebuilding, let the rebuild do it + && !LinksetRoot.IsIncomplete // if waiting for assets or whatever, don't change + && LinksetRoot.PhysShape.HasPhysicalShape // there must be a physical shape assigned + && m_physicsScene.PE.IsCompound(LinksetRoot.PhysShape.physShapeInfo)) + { + // It is possible that the linkset is still under construction and the child is not yet + // inserted into the compound shape. A rebuild of the linkset in a pre-step action will + // build the whole thing with the new position or rotation. + // The index must be checked because Bullet references the child array but does no validity + // checking of the child index passed. + int numLinksetChildren = m_physicsScene.PE.GetNumberOfCompoundChildren(LinksetRoot.PhysShape.physShapeInfo); + if (updated.LinksetChildIndex < numLinksetChildren) { - // Found the child shape within the compound shape - m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, - updated.RawPosition - LinksetRoot.RawPosition, - updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), - true /* shouldRecalculateLocalAabb */); - updatedChild = true; - DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}", - updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation); + BulletShape linksetChildShape = m_physicsScene.PE.GetChildShapeFromCompoundShapeIndex(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex); + if (linksetChildShape.HasPhysicalShape) + { + // Found the child shape within the compound shape + m_physicsScene.PE.UpdateChildTransform(LinksetRoot.PhysShape.physShapeInfo, updated.LinksetChildIndex, + updated.RawPosition - LinksetRoot.RawPosition, + updated.RawOrientation * OMV.Quaternion.Inverse(LinksetRoot.RawOrientation), + true /* shouldRecalculateLocalAabb */); + updatedChild = true; + DetailLog("{0},BSLinksetCompound.UpdateProperties,changeChildPosRot,whichUpdated={1},pos={2},rot={3}", + updated.LocalID, whichUpdated, updated.RawPosition, updated.RawOrientation); + } + else // DEBUG DEBUG + { // DEBUG DEBUG + DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}", + updated.LocalID, linksetChildShape); + } // DEBUG DEBUG } else // DEBUG DEBUG { // DEBUG DEBUG - DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noChildShape,shape={1}", - updated.LocalID, linksetChildShape); + // the child is not yet in the compound shape. This is non-fatal. + DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}", + updated.LocalID, numLinksetChildren, updated.LinksetChildIndex); } // DEBUG DEBUG } else // DEBUG DEBUG { // DEBUG DEBUG - // the child is not yet in the compound shape. This is non-fatal. - DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,childNotInCompoundShape,numChildren={1},index={2}", - updated.LocalID, numLinksetChildren, updated.LinksetChildIndex); + DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID); } // DEBUG DEBUG - } - else // DEBUG DEBUG - { // DEBUG DEBUG - DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild,noBodyOrNotCompound", updated.LocalID); - } // DEBUG DEBUG - - if (!updatedChild) - { - // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info. - // Note: there are several ways through this code that will not update the child if - // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since - // there will already be a rebuild scheduled. - DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", - updated.LocalID, whichUpdated); - Refresh(updated); - } - } - } - } - - // Routine called when rebuilding the body of some member of the linkset. - // If one of the bodies is being changed, the linkset needs rebuilding. - // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated. - // Returns 'true' of something was actually removed and would need restoring - // Called at taint-time!! - public override bool RemoveDependencies(BSPrimLinkable child) - { - bool ret = false; - - DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", - child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); - - Refresh(child); - - return ret; - } - - // ================================================================ - - // Add a new child to the linkset. - // Called while LinkActivity is locked. - protected override void AddChildToLinkset(BSPrimLinkable child) - { - if (!HasChild(child)) - { - m_children.Add(child, new BSLinkInfo(child)); - - DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); - - // Rebuild the compound shape with the new child shape included - Refresh(child); - } - return; - } - - // Remove the specified child from the linkset. - // Safe to call even if the child is not really in the linkset. - protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) - { - child.ClearDisplacement(); - - if (m_children.Remove(child)) - { - DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", - child.LocalID, - LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, - child.LocalID, child.PhysBody.AddrString); - - // Cause the child's body to be rebuilt and thus restored to normal operation - child.ForceBodyShapeRebuild(inTaintTime); - - if (!HasAnyChildren) - { - // The linkset is now empty. The root needs rebuilding. - LinksetRoot.ForceBodyShapeRebuild(inTaintTime); - } - else - { - // Rebuild the compound shape with the child removed - Refresh(LinksetRoot); - } - } - return; - } - - // Called before the simulation step to make sure the compound based linkset - // is all initialized. - // Constraint linksets are rebuilt every time. - // Note that this works for rebuilding just the root after a linkset is taken apart. - // Called at taint time!! - private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape - private void RecomputeLinksetCompound() - { - try - { - Rebuilding = true; - - // No matter what is being done, force the root prim's PhysBody and PhysShape to get set - // to what they should be as if the root was not in a linkset. - // Not that bad since we only get into this routine if there are children in the linkset and - // something has been updated/changed. - // Have to do the rebuild before checking for physical because this might be a linkset - // being destructed and going non-physical. - LinksetRoot.ForceBodyShapeRebuild(true); - - // There is no reason to build all this physical stuff for a non-physical or empty linkset. - if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) - { - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); - return; // Note the 'finally' clause at the botton which will get executed. - } - - // Get a new compound shape to build the linkset shape in. - BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene); - - // Compute a displacement for each component so it is relative to the center-of-mass. - // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass - OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass(); - - OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation)); - OMV.Vector3 origRootPosition = LinksetRoot.RawPosition; - - // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass - OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; - if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass) - { - // Zero everything if center-of-mass displacement is not being done. - centerDisplacementV = OMV.Vector3.Zero; - LinksetRoot.ClearDisplacement(); - } - else - { - // The actual center-of-mass could have been set by the user. - centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV); - } - - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}", - LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV); - - // Add the shapes of all the components of the linkset - int memberIndex = 1; - ForEachMember((cPrim) => - { - if (IsRoot(cPrim)) - { - // Root shape is always index zero. - cPrim.LinksetChildIndex = 0; - } - else - { - cPrim.LinksetChildIndex = memberIndex; - memberIndex++; - } - - // Get a reference to the shape of the child for adding of that shape to the linkset compound shape - BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim); - - // Offset the child shape from the center-of-mass and rotate it to root relative. - OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV; - OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation; - - // Add the child shape to the compound shape being built - if (childShape.physShapeInfo.HasPhysicalShape) - { - m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}", - LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot); - - // Since we are borrowing the shape of the child, disable the origional child body - if (!IsRoot(cPrim)) + + if (!updatedChild) { - m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); - m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION); - // We don't want collisions from the old linkset children. - m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - cPrim.PhysBody.collisionType = CollisionType.LinksetChild; + // If couldn't do the individual child, the linkset needs a rebuild to incorporate the new child info. + // Note: there are several ways through this code that will not update the child if + // the linkset is being rebuilt. In this case, scheduling a rebuild is a NOOP since + // there will already be a rebuild scheduled. + DetailLog("{0},BSLinksetCompound.UpdateProperties,couldNotUpdateChild.schedulingRebuild,whichUpdated={1}", + updated.LocalID, whichUpdated); + Refresh(updated); } } - else - { - // The linkset must be in an intermediate state where all the children have not yet - // been constructed. This sometimes happens on startup when everything is getting - // built and some shapes have to wait for assets to be read in. - // Just skip this linkset for the moment and cause the shape to be rebuilt next tick. - // One problem might be that the shape is broken somehow and it never becomes completely - // available. This might cause the rebuild to happen over and over. - InternalScheduleRebuild(LinksetRoot); - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChildWithNoShape,indx={1},cShape={2},offPos={3},offRot={4}", - LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot); - // Output an annoying warning. It should only happen once but if it keeps coming out, - // the user knows there is something wrong and will report it. - m_physicsScene.Logger.WarnFormat("{0} Linkset rebuild warning. If this happens more than one or two times, please report in Mantis 7191", LogHeader); - m_physicsScene.Logger.WarnFormat("{0} pName={1}, childIdx={2}, shape={3}", - LogHeader, LinksetRoot.Name, cPrim.LinksetChildIndex, childShape); - - // This causes the loop to bail on building the rest of this linkset. - // The rebuild operation will fix it up next tick or declare the object unbuildable. - return true; - } - - return false; // 'false' says to move onto the next child in the list - }); - - // Replace the root shape with the built compound shape. - // Object removed and added to world to get collision cache rebuilt for new shape. - LinksetRoot.PhysShape.Dereference(m_physicsScene); - LinksetRoot.PhysShape = linksetShape; - m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody); - m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo); - m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody); - DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}", - LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape); - m_physicsScene.PE.ResetBroadphasePool(m_physicsScene.World); // DEBUG DEBUG - - // With all of the linkset packed into the root prim, it has the mass of everyone. - LinksetMass = ComputeLinksetMass(); - LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); - - if (UseBulletSimRootOffsetHack) - { - // Enable the physical position updator to return the position and rotation of the root shape. - // This enables a feature in the C++ code to return the world coordinates of the first shape in the - // compound shape. This aleviates the need to offset the returned physical position by the - // center-of-mass offset. - // TODO: either debug this feature or remove it. - m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); } } - finally + + // Routine called when rebuilding the body of some member of the linkset. + // If one of the bodies is being changed, the linkset needs rebuilding. + // For instance, a linkset is built and then a mesh asset is read in and the mesh is recreated. + // Returns 'true' of something was actually removed and would need restoring + // Called at taint-time!! + public override bool RemoveDependencies(BSPrimLinkable child) { - Rebuilding = false; + bool ret = false; + + DetailLog("{0},BSLinksetCompound.RemoveDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", + child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody, IsRoot(child)); + + Refresh(child); + + return ret; + } + + // ================================================================ + + // Add a new child to the linkset. + // Called while LinkActivity is locked. + protected override void AddChildToLinkset(BSPrimLinkable child) + { + if (!HasChild(child)) + { + m_children.Add(child, new BSLinkInfo(child)); + + DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); + + // Rebuild the compound shape with the new child shape included + Refresh(child); + } + return; + } + + // Remove the specified child from the linkset. + // Safe to call even if the child is not really in the linkset. + protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) + { + child.ClearDisplacement(); + + if (m_children.Remove(child)) + { + DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", + child.LocalID, + LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, + child.LocalID, child.PhysBody.AddrString); + + // Cause the child's body to be rebuilt and thus restored to normal operation + child.ForceBodyShapeRebuild(inTaintTime); + + if (!HasAnyChildren) + { + // The linkset is now empty. The root needs rebuilding. + LinksetRoot.ForceBodyShapeRebuild(inTaintTime); + } + else + { + // Rebuild the compound shape with the child removed + Refresh(LinksetRoot); + } + } + return; + } + + // Called before the simulation step to make sure the compound based linkset + // is all initialized. + // Constraint linksets are rebuilt every time. + // Note that this works for rebuilding just the root after a linkset is taken apart. + // Called at taint time!! + private bool UseBulletSimRootOffsetHack = false; // Attempt to have Bullet track the coords of root compound shape + private void RecomputeLinksetCompound() + { + try + { + Rebuilding = true; + + // No matter what is being done, force the root prim's PhysBody and PhysShape to get set + // to what they should be as if the root was not in a linkset. + // Not that bad since we only get into this routine if there are children in the linkset and + // something has been updated/changed. + // Have to do the rebuild before checking for physical because this might be a linkset + // being destructed and going non-physical. + LinksetRoot.ForceBodyShapeRebuild(true); + + // There is no reason to build all this physical stuff for a non-physical or empty linkset. + if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) + { + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); + return; // Note the 'finally' clause at the botton which will get executed. + } + + // Get a new compound shape to build the linkset shape in. + BSShape linksetShape = BSShapeCompound.GetReference(m_physicsScene); + + // Compute a displacement for each component so it is relative to the center-of-mass. + // Bullet presumes an object's origin (relative <0,0,0>) is its center-of-mass + OMV.Vector3 centerOfMassW = ComputeLinksetCenterOfMass(); + + OMV.Quaternion invRootOrientation = OMV.Quaternion.Normalize(OMV.Quaternion.Inverse(LinksetRoot.RawOrientation)); + OMV.Vector3 origRootPosition = LinksetRoot.RawPosition; + + // 'centerDisplacementV' is the vehicle relative distance from the simulator root position to the center-of-mass + OMV.Vector3 centerDisplacementV = (centerOfMassW - LinksetRoot.RawPosition) * invRootOrientation; + if (UseBulletSimRootOffsetHack || !BSParam.LinksetOffsetCenterOfMass) + { + // Zero everything if center-of-mass displacement is not being done. + centerDisplacementV = OMV.Vector3.Zero; + LinksetRoot.ClearDisplacement(); + } + else + { + // The actual center-of-mass could have been set by the user. + centerDisplacementV = LinksetRoot.SetEffectiveCenterOfMassDisplacement(centerDisplacementV); + } + + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,COM,rootPos={1},com={2},comDisp={3}", + LinksetRoot.LocalID, origRootPosition, centerOfMassW, centerDisplacementV); + + // Add the shapes of all the components of the linkset + int memberIndex = 1; + ForEachMember((cPrim) => + { + if (IsRoot(cPrim)) + { + // Root shape is always index zero. + cPrim.LinksetChildIndex = 0; + } + else + { + cPrim.LinksetChildIndex = memberIndex; + memberIndex++; + } + + // Get a reference to the shape of the child for adding of that shape to the linkset compound shape + BSShape childShape = cPrim.PhysShape.GetReference(m_physicsScene, cPrim); + + // Offset the child shape from the center-of-mass and rotate it to root relative. + OMV.Vector3 offsetPos = (cPrim.RawPosition - origRootPosition) * invRootOrientation - centerDisplacementV; + OMV.Quaternion offsetRot = OMV.Quaternion.Normalize(cPrim.RawOrientation) * invRootOrientation; + + // Add the child shape to the compound shape being built + if (childShape.physShapeInfo.HasPhysicalShape) + { + m_physicsScene.PE.AddChildShapeToCompoundShape(linksetShape.physShapeInfo, childShape.physShapeInfo, offsetPos, offsetRot); + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChild,indx={1},cShape={2},offPos={3},offRot={4}", + LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot); + + // Since we are borrowing the shape of the child, disable the origional child body + if (!IsRoot(cPrim)) + { + m_physicsScene.PE.AddToCollisionFlags(cPrim.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); + m_physicsScene.PE.ForceActivationState(cPrim.PhysBody, ActivationState.DISABLE_SIMULATION); + // We don't want collisions from the old linkset children. + m_physicsScene.PE.RemoveFromCollisionFlags(cPrim.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + cPrim.PhysBody.collisionType = CollisionType.LinksetChild; + } + } + else + { + // The linkset must be in an intermediate state where all the children have not yet + // been constructed. This sometimes happens on startup when everything is getting + // built and some shapes have to wait for assets to be read in. + // Just skip this linkset for the moment and cause the shape to be rebuilt next tick. + // One problem might be that the shape is broken somehow and it never becomes completely + // available. This might cause the rebuild to happen over and over. + InternalScheduleRebuild(LinksetRoot); + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addChildWithNoShape,indx={1},cShape={2},offPos={3},offRot={4}", + LinksetRoot.LocalID, cPrim.LinksetChildIndex, childShape, offsetPos, offsetRot); + // Output an annoying warning. It should only happen once but if it keeps coming out, + // the user knows there is something wrong and will report it. + m_physicsScene.Logger.WarnFormat("{0} Linkset rebuild warning. If this happens more than one or two times, please report in Mantis 7191", LogHeader); + m_physicsScene.Logger.WarnFormat("{0} pName={1}, childIdx={2}, shape={3}", + LogHeader, LinksetRoot.Name, cPrim.LinksetChildIndex, childShape); + + // This causes the loop to bail on building the rest of this linkset. + // The rebuild operation will fix it up next tick or declare the object unbuildable. + return true; + } + + return false; // 'false' says to move onto the next child in the list + }); + + // Replace the root shape with the built compound shape. + // Object removed and added to world to get collision cache rebuilt for new shape. + LinksetRoot.PhysShape.Dereference(m_physicsScene); + LinksetRoot.PhysShape = linksetShape; + m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, LinksetRoot.PhysBody); + m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, LinksetRoot.PhysBody, linksetShape.physShapeInfo); + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, LinksetRoot.PhysBody); + DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addBody,body={1},shape={2}", + LinksetRoot.LocalID, LinksetRoot.PhysBody, linksetShape); + m_physicsScene.PE.ResetBroadphasePool(m_physicsScene.World); // DEBUG DEBUG + + // With all of the linkset packed into the root prim, it has the mass of everyone. + LinksetMass = ComputeLinksetMass(); + LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true); + + if (UseBulletSimRootOffsetHack) + { + // Enable the physical position updator to return the position and rotation of the root shape. + // This enables a feature in the C++ code to return the world coordinates of the first shape in the + // compound shape. This aleviates the need to offset the returned physical position by the + // center-of-mass offset. + // TODO: either debug this feature or remove it. + m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, CollisionFlags.BS_RETURN_ROOT_COMPOUND_SHAPE); + } + } + finally + { + Rebuilding = false; + } + + // See that the Aabb surrounds the new shape + m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); } - - // See that the Aabb surrounds the new shape - m_physicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape.physShapeInfo); } -} } \ No newline at end of file diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs index c4b4c86ec8..fe1ba079fc 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs @@ -32,821 +32,820 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -public sealed class BSLinksetConstraints : BSLinkset -{ - // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; - - public class BSLinkInfoConstraint : BSLinkInfo + public sealed class BSLinksetConstraints : BSLinkset { - public ConstraintType constraintType; - public BSConstraint constraint; - public OMV.Vector3 linearLimitLow; - public OMV.Vector3 linearLimitHigh; - public OMV.Vector3 angularLimitLow; - public OMV.Vector3 angularLimitHigh; - public bool useFrameOffset; - public bool enableTransMotor; - public float transMotorMaxVel; - public float transMotorMaxForce; - public float cfm; - public float erp; - public float solverIterations; - // - public OMV.Vector3 frameInAloc; - public OMV.Quaternion frameInArot; - public OMV.Vector3 frameInBloc; - public OMV.Quaternion frameInBrot; - public bool useLinearReferenceFrameA; - // Spring - public bool[] springAxisEnable; - public float[] springDamping; - public float[] springStiffness; - public OMV.Vector3 springLinearEquilibriumPoint; - public OMV.Vector3 springAngularEquilibriumPoint; + // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; - public BSLinkInfoConstraint(BSPrimLinkable pMember) - : base(pMember) + public class BSLinkInfoConstraint : BSLinkInfo { - constraint = null; - ResetLink(); - member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID); - } + public ConstraintType constraintType; + public BSConstraint constraint; + public OMV.Vector3 linearLimitLow; + public OMV.Vector3 linearLimitHigh; + public OMV.Vector3 angularLimitLow; + public OMV.Vector3 angularLimitHigh; + public bool useFrameOffset; + public bool enableTransMotor; + public float transMotorMaxVel; + public float transMotorMaxForce; + public float cfm; + public float erp; + public float solverIterations; + // + public OMV.Vector3 frameInAloc; + public OMV.Quaternion frameInArot; + public OMV.Vector3 frameInBloc; + public OMV.Quaternion frameInBrot; + public bool useLinearReferenceFrameA; + // Spring + public bool[] springAxisEnable; + public float[] springDamping; + public float[] springStiffness; + public OMV.Vector3 springLinearEquilibriumPoint; + public OMV.Vector3 springAngularEquilibriumPoint; - // Set all the parameters for this constraint to a fixed, non-movable constraint. - public override void ResetLink() - { - // constraintType = ConstraintType.D6_CONSTRAINT_TYPE; - constraintType = ConstraintType.BS_FIXED_CONSTRAINT_TYPE; - linearLimitLow = OMV.Vector3.Zero; - linearLimitHigh = OMV.Vector3.Zero; - angularLimitLow = OMV.Vector3.Zero; - angularLimitHigh = OMV.Vector3.Zero; - useFrameOffset = BSParam.LinkConstraintUseFrameOffset; - enableTransMotor = BSParam.LinkConstraintEnableTransMotor; - transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; - transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; - cfm = BSParam.LinkConstraintCFM; - erp = BSParam.LinkConstraintERP; - solverIterations = BSParam.LinkConstraintSolverIterations; - frameInAloc = OMV.Vector3.Zero; - frameInArot = OMV.Quaternion.Identity; - frameInBloc = OMV.Vector3.Zero; - frameInBrot = OMV.Quaternion.Identity; - useLinearReferenceFrameA = true; - springAxisEnable = new bool[6]; - springDamping = new float[6]; - springStiffness = new float[6]; - for (int ii = 0; ii < springAxisEnable.Length; ii++) + public BSLinkInfoConstraint(BSPrimLinkable pMember) + : base(pMember) { - springAxisEnable[ii] = false; - springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; - springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; + constraint = null; + ResetLink(); + member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID); + } + + // Set all the parameters for this constraint to a fixed, non-movable constraint. + public override void ResetLink() + { + // constraintType = ConstraintType.D6_CONSTRAINT_TYPE; + constraintType = ConstraintType.BS_FIXED_CONSTRAINT_TYPE; + linearLimitLow = OMV.Vector3.Zero; + linearLimitHigh = OMV.Vector3.Zero; + angularLimitLow = OMV.Vector3.Zero; + angularLimitHigh = OMV.Vector3.Zero; + useFrameOffset = BSParam.LinkConstraintUseFrameOffset; + enableTransMotor = BSParam.LinkConstraintEnableTransMotor; + transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; + transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; + cfm = BSParam.LinkConstraintCFM; + erp = BSParam.LinkConstraintERP; + solverIterations = BSParam.LinkConstraintSolverIterations; + frameInAloc = OMV.Vector3.Zero; + frameInArot = OMV.Quaternion.Identity; + frameInBloc = OMV.Vector3.Zero; + frameInBrot = OMV.Quaternion.Identity; + useLinearReferenceFrameA = true; + springAxisEnable = new bool[6]; + springDamping = new float[6]; + springStiffness = new float[6]; + for (int ii = 0; ii < springAxisEnable.Length; ii++) + { + springAxisEnable[ii] = false; + springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; + springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; + } + springLinearEquilibriumPoint = OMV.Vector3.Zero; + springAngularEquilibriumPoint = OMV.Vector3.Zero; + member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID); + } + + // Given a constraint, apply the current constraint parameters to same. + public override void SetLinkParameters(BSConstraint constrain) + { + member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType); + switch (constraintType) + { + case ConstraintType.BS_FIXED_CONSTRAINT_TYPE: + case ConstraintType.D6_CONSTRAINT_TYPE: + BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof; + if (constrain6dof != null) + { + // NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code. + // zero linear and angular limits makes the objects unable to move in relation to each other + constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh); + constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh); + + // tweek the constraint to increase stability + constrain6dof.UseFrameOffset(useFrameOffset); + constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); + constrain6dof.SetCFMAndERP(cfm, erp); + if (solverIterations != 0f) + { + constrain6dof.SetSolverIterations(solverIterations); + } + } + break; + case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: + BSConstraintSpring constrainSpring = constrain as BSConstraintSpring; + if (constrainSpring != null) + { + // zero linear and angular limits makes the objects unable to move in relation to each other + constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh); + constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh); + + // tweek the constraint to increase stability + constrainSpring.UseFrameOffset(useFrameOffset); + constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); + constrainSpring.SetCFMAndERP(cfm, erp); + if (solverIterations != 0f) + { + constrainSpring.SetSolverIterations(solverIterations); + } + for (int ii = 0; ii < springAxisEnable.Length; ii++) + { + constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]); + if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) + constrainSpring.SetDamping(ii, springDamping[ii]); + if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) + constrainSpring.SetStiffness(ii, springStiffness[ii]); + } + constrainSpring.CalculateTransforms(); + + if (springLinearEquilibriumPoint != OMV.Vector3.Zero) + constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint); + else + constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED); + } + break; + default: + break; + } + } + + // Return 'true' if the property updates from the physics engine should be reported + // to the simulator. + // If the constraint is fixed, we don't need to report as the simulator and viewer will + // report the right things. + public override bool ShouldUpdateChildProperties() + { + bool ret = true; + if (constraintType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE) + ret = false; + + return ret; } - springLinearEquilibriumPoint = OMV.Vector3.Zero; - springAngularEquilibriumPoint = OMV.Vector3.Zero; - member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID); } - // Given a constraint, apply the current constraint parameters to same. - public override void SetLinkParameters(BSConstraint constrain) + public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) { - member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType); - switch (constraintType) + LinksetImpl = LinksetImplementation.Constraint; + } + + private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]"; + + // When physical properties are changed the linkset needs to recalculate + // its internal properties. + // This is queued in the 'post taint' queue so the + // refresh will happen once after all the other taints are applied. + public override void Refresh(BSPrimLinkable requestor) + { + ScheduleRebuild(requestor); + base.Refresh(requestor); + + } + + private void ScheduleRebuild(BSPrimLinkable requestor) + { + DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", + requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); + + // When rebuilding, it is possible to set properties that would normally require a rebuild. + // If already rebuilding, don't request another rebuild. + // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. + lock (this) + { + if (!RebuildScheduled) + { + if (!Rebuilding && HasAnyChildren) + { + RebuildScheduled = true; + // Queue to happen after all the other taint processing + m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() + { + if (HasAnyChildren) + { + // Constraints that have not been changed are not rebuild but make sure + // the constraint of the requestor is rebuilt. + PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor); + // Rebuild the linkset and all its constraints. + RecomputeLinksetConstraints(); + } + RebuildScheduled = false; + }); + } + } + } + } + + // The object is going dynamic (physical). Do any setup necessary + // for a dynamic linkset. + // Only the state of the passed object can be modified. The rest of the linkset + // has not yet been fully constructed. + // Return 'true' if any properties updated on the passed object. + // Called at taint-time! + public override bool MakeDynamic(BSPrimLinkable child) + { + bool ret = false; + DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); + if (IsRoot(child)) + { + // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. + Refresh(LinksetRoot); + } + return ret; + } + + // The object is going static (non-physical). Do any setup necessary for a static linkset. + // Return 'true' if any properties updated on the passed object. + // This doesn't normally happen -- OpenSim removes the objects from the physical + // world if it is a static linkset. + // Called at taint-time! + public override bool MakeStatic(BSPrimLinkable child) + { + bool ret = false; + + DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); + child.ClearDisplacement(); + if (IsRoot(child)) + { + // Schedule a rebuild to verify that the root shape is set to the real shape. + Refresh(LinksetRoot); + } + return ret; + } + + // Called at taint-time!! + public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj) + { + // Nothing to do for constraints on property updates + } + + // Routine called when rebuilding the body of some member of the linkset. + // Destroy all the constraints have have been made to root and set + // up to rebuild the constraints before the next simulation step. + // Returns 'true' of something was actually removed and would need restoring + // Called at taint-time!! + public override bool RemoveDependencies(BSPrimLinkable child) + { + bool ret = false; + + DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}", + child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); + + lock (m_linksetActivityLock) + { + // Just undo all the constraints for this linkset. Rebuild at the end of the step. + ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); + // Cause the constraints, et al to be rebuilt before the next simulation step. + Refresh(LinksetRoot); + } + return ret; + } + + // ================================================================ + + // Add a new child to the linkset. + // Called while LinkActivity is locked. + protected override void AddChildToLinkset(BSPrimLinkable child) + { + if (!HasChild(child)) + { + m_children.Add(child, new BSLinkInfoConstraint(child)); + + DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); + + // Cause constraints and assorted properties to be recomputed before the next simulation step. + Refresh(LinksetRoot); + } + return; + } + + // Remove the specified child from the linkset. + // Safe to call even if the child is not really in my linkset. + protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) + { + if (m_children.Remove(child)) + { + BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now + BSPrimLinkable childx = child; + + DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", + childx.LocalID, + rootx.LocalID, rootx.PhysBody.AddrString, + childx.LocalID, childx.PhysBody.AddrString); + + m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate() + { + PhysicallyUnlinkAChildFromRoot(rootx, childx); + }); + // See that the linkset parameters are recomputed at the end of the taint time. + Refresh(LinksetRoot); + } + else + { + // Non-fatal occurance. + // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); + } + return; + } + + // Create a constraint between me (root of linkset) and the passed prim (the child). + // Called at taint time! + private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) + { + // Don't build the constraint when asked. Put it off until just before the simulation step. + Refresh(rootPrim); + } + + // Create a static constraint between the two passed objects + private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li) + { + BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint; + if (linkInfo == null) + return null; + + // Zero motion for children so they don't interpolate + li.member.ZeroMotion(true); + + BSConstraint constrain = null; + + switch (linkInfo.constraintType) { case ConstraintType.BS_FIXED_CONSTRAINT_TYPE: case ConstraintType.D6_CONSTRAINT_TYPE: - BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof; - if (constrain6dof != null) - { - // NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code. - // zero linear and angular limits makes the objects unable to move in relation to each other - constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh); - constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh); + // Relative position normalized to the root prim + // Essentually a vector pointing from center of rootPrim to center of li.member + OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position; + + // real world coordinate of midpoint between the two objects + OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); + + DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}", + rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody, + rootPrim.Position, linkInfo.member.Position, midPoint); + + // create a constraint that allows no freedom of movement between the two objects + // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 + + constrain = new BSConstraint6Dof( + m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true ); + + /* NOTE: below is an attempt to build constraint with full frame computation, etc. + * Using the midpoint is easier since it lets the Bullet code manipulate the transforms + * of the objects. + * Code left for future programmers. + // ================================================================================== + // relative position normalized to the root prim + OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); + OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation; + + // relative rotation of the child to the parent + OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation; + OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); + + DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID); + constrain = new BS6DofConstraint( + PhysicsScene.World, rootPrim.Body, liConstraint.member.Body, + OMV.Vector3.Zero, + OMV.Quaternion.Inverse(rootPrim.Orientation), + OMV.Vector3.Zero, + OMV.Quaternion.Inverse(liConstraint.member.Orientation), + true, + true + ); + // ================================================================================== + */ - // tweek the constraint to increase stability - constrain6dof.UseFrameOffset(useFrameOffset); - constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); - constrain6dof.SetCFMAndERP(cfm, erp); - if (solverIterations != 0f) - { - constrain6dof.SetSolverIterations(solverIterations); - } - } break; case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: - BSConstraintSpring constrainSpring = constrain as BSConstraintSpring; - if (constrainSpring != null) - { - // zero linear and angular limits makes the objects unable to move in relation to each other - constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh); - constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh); + constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, + linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot, + linkInfo.useLinearReferenceFrameA, + true /*disableCollisionsBetweenLinkedBodies*/); + DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}", + rootPrim.LocalID, + rootPrim.LocalID, rootPrim.PhysBody.AddrString, + linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString, + rootPrim.Position, linkInfo.member.Position); - // tweek the constraint to increase stability - constrainSpring.UseFrameOffset(useFrameOffset); - constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); - constrainSpring.SetCFMAndERP(cfm, erp); - if (solverIterations != 0f) - { - constrainSpring.SetSolverIterations(solverIterations); - } - for (int ii = 0; ii < springAxisEnable.Length; ii++) - { - constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]); - if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) - constrainSpring.SetDamping(ii, springDamping[ii]); - if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) - constrainSpring.SetStiffness(ii, springStiffness[ii]); - } - constrainSpring.CalculateTransforms(); - - if (springLinearEquilibriumPoint != OMV.Vector3.Zero) - constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint); - else - constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED); - } break; default: break; } + + linkInfo.SetLinkParameters(constrain); + + m_physicsScene.Constraints.AddConstraint(constrain); + + return constrain; } - // Return 'true' if the property updates from the physics engine should be reported - // to the simulator. - // If the constraint is fixed, we don't need to report as the simulator and viewer will - // report the right things. - public override bool ShouldUpdateChildProperties() + // Remove linkage between the linkset root and a particular child + // The root and child bodies are passed in because we need to remove the constraint between + // the bodies that were present at unlink time. + // Called at taint time! + private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) { - bool ret = true; - if (constraintType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE) - ret = false; + bool ret = false; + DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", + rootPrim.LocalID, + rootPrim.LocalID, rootPrim.PhysBody.AddrString, + childPrim.LocalID, childPrim.PhysBody.AddrString); + + // If asked to unlink root from root, just remove all the constraints + if (rootPrim == childPrim || childPrim == LinksetRoot) + { + PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); + ret = true; + } + else + { + // Find the constraint for this link and get rid of it from the overall collection and from my list + if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) + { + // Make the child refresh its location + m_physicsScene.PE.PushUpdate(childPrim.PhysBody); + ret = true; + } + } return ret; } - } - public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) - { - LinksetImpl = LinksetImplementation.Constraint; - } - - private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]"; - - // When physical properties are changed the linkset needs to recalculate - // its internal properties. - // This is queued in the 'post taint' queue so the - // refresh will happen once after all the other taints are applied. - public override void Refresh(BSPrimLinkable requestor) - { - ScheduleRebuild(requestor); - base.Refresh(requestor); - - } - - private void ScheduleRebuild(BSPrimLinkable requestor) - { - DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", - requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); - - // When rebuilding, it is possible to set properties that would normally require a rebuild. - // If already rebuilding, don't request another rebuild. - // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. - lock (this) + // Remove linkage between myself and any possible children I might have. + // Returns 'true' of any constraints were destroyed. + // Called at taint time! + private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim) { - if (!RebuildScheduled) + DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); + + return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); + } + + // Call each of the constraints that make up this linkset and recompute the + // various transforms and variables. Create constraints of not created yet. + // Called before the simulation step to make sure the constraint based linkset + // is all initialized. + // Called at taint time!! + private void RecomputeLinksetConstraints() + { + float linksetMass = LinksetMass; + LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true); + + DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", + LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); + + try { - if (!Rebuilding && HasAnyChildren) + Rebuilding = true; + + // There is no reason to build all this physical stuff for a non-physical linkset. + if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) { - RebuildScheduled = true; - // Queue to happen after all the other taint processing - m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() + DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); + return; // Note the 'finally' clause at the botton which will get executed. + } + + ForEachLinkInfo((li) => + { + // A child in the linkset physically shows the mass of the whole linkset. + // This allows Bullet to apply enough force on the child to move the whole linkset. + // (Also do the mass stuff before recomputing the constraint so mass is not zero.) + li.member.UpdatePhysicalMassProperties(linksetMass, true); + + BSConstraint constrain; + if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain)) { - if (HasAnyChildren) + // If constraint doesn't exist yet, create it. + constrain = BuildConstraint(LinksetRoot, li); + } + li.SetLinkParameters(constrain); + constrain.RecomputeConstraintVariables(linksetMass); + + // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG + return false; // 'false' says to keep processing other members + }); + } + finally + { + Rebuilding = false; + } + } + + #region Extension + public override object Extension(string pFunct, params object[] pParams) + { + object ret = null; + switch (pFunct) + { + // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ] + case ExtendedPhysics.PhysFunctChangeLinkType: + if (pParams.Length > 2) + { + int requestedType = (int)pParams[2]; + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType); + if (requestedType == (int)ConstraintType.BS_FIXED_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE + || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE) { - // Constraints that have not been changed are not rebuild but make sure - // the constraint of the requestor is rebuilt. - PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor); - // Rebuild the linkset and all its constraints. - RecomputeLinksetConstraints(); + BSPrimLinkable child = pParams[1] as BSPrimLinkable; + if (child != null) + { + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}", + LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType); + m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate() + { + // Pick up all the constraints currently created. + RemoveDependencies(child); + + BSLinkInfo linkInfo = null; + if (TryGetLinkInfo(child, out linkInfo)) + { + BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; + if (linkInfoC != null) + { + linkInfoC.constraintType = (ConstraintType)requestedType; + ret = (object)true; + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}", + linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); + } + else + { + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID); + } + } + else + { + DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID); + } + // Cause the whole linkset to be rebuilt in post-taint time. + Refresh(child); + }); + } + else + { + DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID); + } } - RebuildScheduled = false; - }); - } - } - } - } - - // The object is going dynamic (physical). Do any setup necessary - // for a dynamic linkset. - // Only the state of the passed object can be modified. The rest of the linkset - // has not yet been fully constructed. - // Return 'true' if any properties updated on the passed object. - // Called at taint-time! - public override bool MakeDynamic(BSPrimLinkable child) - { - bool ret = false; - DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); - if (IsRoot(child)) - { - // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. - Refresh(LinksetRoot); - } - return ret; - } - - // The object is going static (non-physical). Do any setup necessary for a static linkset. - // Return 'true' if any properties updated on the passed object. - // This doesn't normally happen -- OpenSim removes the objects from the physical - // world if it is a static linkset. - // Called at taint-time! - public override bool MakeStatic(BSPrimLinkable child) - { - bool ret = false; - - DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); - child.ClearDisplacement(); - if (IsRoot(child)) - { - // Schedule a rebuild to verify that the root shape is set to the real shape. - Refresh(LinksetRoot); - } - return ret; - } - - // Called at taint-time!! - public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj) - { - // Nothing to do for constraints on property updates - } - - // Routine called when rebuilding the body of some member of the linkset. - // Destroy all the constraints have have been made to root and set - // up to rebuild the constraints before the next simulation step. - // Returns 'true' of something was actually removed and would need restoring - // Called at taint-time!! - public override bool RemoveDependencies(BSPrimLinkable child) - { - bool ret = false; - - DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}", - child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); - - lock (m_linksetActivityLock) - { - // Just undo all the constraints for this linkset. Rebuild at the end of the step. - ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); - // Cause the constraints, et al to be rebuilt before the next simulation step. - Refresh(LinksetRoot); - } - return ret; - } - - // ================================================================ - - // Add a new child to the linkset. - // Called while LinkActivity is locked. - protected override void AddChildToLinkset(BSPrimLinkable child) - { - if (!HasChild(child)) - { - m_children.Add(child, new BSLinkInfoConstraint(child)); - - DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); - - // Cause constraints and assorted properties to be recomputed before the next simulation step. - Refresh(LinksetRoot); - } - return; - } - - // Remove the specified child from the linkset. - // Safe to call even if the child is not really in my linkset. - protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) - { - if (m_children.Remove(child)) - { - BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now - BSPrimLinkable childx = child; - - DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", - childx.LocalID, - rootx.LocalID, rootx.PhysBody.AddrString, - childx.LocalID, childx.PhysBody.AddrString); - - m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate() - { - PhysicallyUnlinkAChildFromRoot(rootx, childx); - }); - // See that the linkset parameters are recomputed at the end of the taint time. - Refresh(LinksetRoot); - } - else - { - // Non-fatal occurance. - // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); - } - return; - } - - // Create a constraint between me (root of linkset) and the passed prim (the child). - // Called at taint time! - private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) - { - // Don't build the constraint when asked. Put it off until just before the simulation step. - Refresh(rootPrim); - } - - // Create a static constraint between the two passed objects - private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li) - { - BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint; - if (linkInfo == null) - return null; - - // Zero motion for children so they don't interpolate - li.member.ZeroMotion(true); - - BSConstraint constrain = null; - - switch (linkInfo.constraintType) - { - case ConstraintType.BS_FIXED_CONSTRAINT_TYPE: - case ConstraintType.D6_CONSTRAINT_TYPE: - // Relative position normalized to the root prim - // Essentually a vector pointing from center of rootPrim to center of li.member - OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position; - - // real world coordinate of midpoint between the two objects - OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); - - DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}", - rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody, - rootPrim.Position, linkInfo.member.Position, midPoint); - - // create a constraint that allows no freedom of movement between the two objects - // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 - - constrain = new BSConstraint6Dof( - m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true ); - - /* NOTE: below is an attempt to build constraint with full frame computation, etc. - * Using the midpoint is easier since it lets the Bullet code manipulate the transforms - * of the objects. - * Code left for future programmers. - // ================================================================================== - // relative position normalized to the root prim - OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); - OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation; - - // relative rotation of the child to the parent - OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation; - OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); - - DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID); - constrain = new BS6DofConstraint( - PhysicsScene.World, rootPrim.Body, liConstraint.member.Body, - OMV.Vector3.Zero, - OMV.Quaternion.Inverse(rootPrim.Orientation), - OMV.Vector3.Zero, - OMV.Quaternion.Inverse(liConstraint.member.Orientation), - true, - true - ); - // ================================================================================== - */ - - break; - case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: - constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, - linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot, - linkInfo.useLinearReferenceFrameA, - true /*disableCollisionsBetweenLinkedBodies*/); - DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}", - rootPrim.LocalID, - rootPrim.LocalID, rootPrim.PhysBody.AddrString, - linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString, - rootPrim.Position, linkInfo.member.Position); - - break; - default: - break; - } - - linkInfo.SetLinkParameters(constrain); - - m_physicsScene.Constraints.AddConstraint(constrain); - - return constrain; - } - - // Remove linkage between the linkset root and a particular child - // The root and child bodies are passed in because we need to remove the constraint between - // the bodies that were present at unlink time. - // Called at taint time! - private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) - { - bool ret = false; - DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", - rootPrim.LocalID, - rootPrim.LocalID, rootPrim.PhysBody.AddrString, - childPrim.LocalID, childPrim.PhysBody.AddrString); - - // If asked to unlink root from root, just remove all the constraints - if (rootPrim == childPrim || childPrim == LinksetRoot) - { - PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); - ret = true; - } - else - { - // Find the constraint for this link and get rid of it from the overall collection and from my list - if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) - { - // Make the child refresh its location - m_physicsScene.PE.PushUpdate(childPrim.PhysBody); - ret = true; - } - } - - return ret; - } - - // Remove linkage between myself and any possible children I might have. - // Returns 'true' of any constraints were destroyed. - // Called at taint time! - private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim) - { - DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); - - return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); - } - - // Call each of the constraints that make up this linkset and recompute the - // various transforms and variables. Create constraints of not created yet. - // Called before the simulation step to make sure the constraint based linkset - // is all initialized. - // Called at taint time!! - private void RecomputeLinksetConstraints() - { - float linksetMass = LinksetMass; - LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true); - - DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", - LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); - - try - { - Rebuilding = true; - - // There is no reason to build all this physical stuff for a non-physical linkset. - if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) - { - DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); - return; // Note the 'finally' clause at the botton which will get executed. - } - - ForEachLinkInfo((li) => - { - // A child in the linkset physically shows the mass of the whole linkset. - // This allows Bullet to apply enough force on the child to move the whole linkset. - // (Also do the mass stuff before recomputing the constraint so mass is not zero.) - li.member.UpdatePhysicalMassProperties(linksetMass, true); - - BSConstraint constrain; - if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain)) - { - // If constraint doesn't exist yet, create it. - constrain = BuildConstraint(LinksetRoot, li); - } - li.SetLinkParameters(constrain); - constrain.RecomputeConstraintVariables(linksetMass); - - // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG - return false; // 'false' says to keep processing other members - }); - } - finally - { - Rebuilding = false; - } - } - - #region Extension - public override object Extension(string pFunct, params object[] pParams) - { - object ret = null; - switch (pFunct) - { - // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ] - case ExtendedPhysics.PhysFunctChangeLinkType: - if (pParams.Length > 2) - { - int requestedType = (int)pParams[2]; - DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType); - if (requestedType == (int)ConstraintType.BS_FIXED_CONSTRAINT_TYPE - || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE - || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE - || requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE - || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE - || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE) + else + { + DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}", + LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE)); + } + } + break; + // pParams = [ BSPhysObject root, BSPhysObject child ] + case ExtendedPhysics.PhysFunctGetLinkType: + if (pParams.Length > 0) { BSPrimLinkable child = pParams[1] as BSPrimLinkable; if (child != null) { - DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}", - LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType); - m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate() + BSLinkInfo linkInfo = null; + if (TryGetLinkInfo(child, out linkInfo)) { - // Pick up all the constraints currently created. - RemoveDependencies(child); - - BSLinkInfo linkInfo = null; - if (TryGetLinkInfo(child, out linkInfo)) + BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; + if (linkInfoC != null) { - BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; - if (linkInfoC != null) - { - linkInfoC.constraintType = (ConstraintType)requestedType; - ret = (object)true; - DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}", - linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); - } - else - { - DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID); - } - } - else - { - DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID); - } - // Cause the whole linkset to be rebuilt in post-taint time. - Refresh(child); - }); - } - else - { - DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID); - } - } - else - { - DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}", - LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE)); - } - } - break; - // pParams = [ BSPhysObject root, BSPhysObject child ] - case ExtendedPhysics.PhysFunctGetLinkType: - if (pParams.Length > 0) - { - BSPrimLinkable child = pParams[1] as BSPrimLinkable; - if (child != null) - { - BSLinkInfo linkInfo = null; - if (TryGetLinkInfo(child, out linkInfo)) - { - BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; - if (linkInfoC != null) - { - ret = (object)(int)linkInfoC.constraintType; - DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}", - linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); + ret = (object)(int)linkInfoC.constraintType; + DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}", + linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); + } } } } - } - break; - // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ] - case ExtendedPhysics.PhysFunctChangeLinkParams: - // There should be two parameters: the childActor and a list of parameters to set - if (pParams.Length > 2) - { - BSPrimLinkable child = pParams[1] as BSPrimLinkable; - BSLinkInfo baseLinkInfo = null; - if (TryGetLinkInfo(child, out baseLinkInfo)) + break; + // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ] + case ExtendedPhysics.PhysFunctChangeLinkParams: + // There should be two parameters: the childActor and a list of parameters to set + if (pParams.Length > 2) { - BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint; - if (linkInfo != null) + BSPrimLinkable child = pParams[1] as BSPrimLinkable; + BSLinkInfo baseLinkInfo = null; + if (TryGetLinkInfo(child, out baseLinkInfo)) { - int valueInt; - float valueFloat; - bool valueBool; - OMV.Vector3 valueVector; - OMV.Vector3 valueVector2; - OMV.Quaternion valueQuaternion; - int axisLow, axisHigh; - - int opIndex = 2; - while (opIndex < pParams.Length) + BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint; + if (linkInfo != null) { - int thisOp = 0; - string errMsg = ""; - try + int valueInt; + float valueFloat; + bool valueBool; + OMV.Vector3 valueVector; + OMV.Vector3 valueVector2; + OMV.Quaternion valueQuaternion; + int axisLow, axisHigh; + + int opIndex = 2; + while (opIndex < pParams.Length) { - thisOp = (int)pParams[opIndex]; - DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}", - linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]); - switch (thisOp) + int thisOp = 0; + string errMsg = ""; + try { - case ExtendedPhysics.PHYS_PARAM_LINK_TYPE: - valueInt = (int)pParams[opIndex + 1]; - ConstraintType valueType = (ConstraintType)valueInt; - if (valueType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE - || valueType == ConstraintType.D6_CONSTRAINT_TYPE - || valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE - || valueType == ConstraintType.HINGE_CONSTRAINT_TYPE - || valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE - || valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE) - { - linkInfo.constraintType = valueType; - } - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC: - errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector"; - valueVector = (OMV.Vector3)pParams[opIndex + 1]; - linkInfo.frameInAloc = valueVector; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT: - errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation"; - valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; - linkInfo.frameInArot = valueQuaternion; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC: - errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector"; - valueVector = (OMV.Vector3)pParams[opIndex + 1]; - linkInfo.frameInBloc = valueVector; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT: - errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation"; - valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; - linkInfo.frameInBrot = valueQuaternion; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW: - errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector"; - valueVector = (OMV.Vector3)pParams[opIndex + 1]; - linkInfo.linearLimitLow = valueVector; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH: - errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector"; - valueVector = (OMV.Vector3)pParams[opIndex + 1]; - linkInfo.linearLimitHigh = valueVector; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW: - errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector"; - valueVector = (OMV.Vector3)pParams[opIndex + 1]; - linkInfo.angularLimitLow = valueVector; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH: - errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector"; - valueVector = (OMV.Vector3)pParams[opIndex + 1]; - linkInfo.angularLimitHigh = valueVector; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET: - errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)"; - valueBool = ((int)pParams[opIndex + 1]) != 0; - linkInfo.useFrameOffset = valueBool; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR: - errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)"; - valueBool = ((int)pParams[opIndex + 1]) != 0; - linkInfo.enableTransMotor = valueBool; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL: - errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float"; - valueFloat = (float)pParams[opIndex + 1]; - linkInfo.transMotorMaxVel = valueFloat; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE: - errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float"; - valueFloat = (float)pParams[opIndex + 1]; - linkInfo.transMotorMaxForce = valueFloat; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_CFM: - errMsg = "PHYS_PARAM_CFM takes one parameter of type float"; - valueFloat = (float)pParams[opIndex + 1]; - linkInfo.cfm = valueFloat; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_ERP: - errMsg = "PHYS_PARAM_ERP takes one parameter of type float"; - valueFloat = (float)pParams[opIndex + 1]; - linkInfo.erp = valueFloat; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS: - errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float"; - valueFloat = (float)pParams[opIndex + 1]; - linkInfo.solverIterations = valueFloat; - opIndex += 2; - break; - case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE: - errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)"; - valueInt = (int)pParams[opIndex + 1]; - valueBool = ((int)pParams[opIndex + 2]) != 0; - GetAxisRange(valueInt, out axisLow, out axisHigh); - for (int ii = axisLow; ii <= axisHigh; ii++) - linkInfo.springAxisEnable[ii] = valueBool; - opIndex += 3; - break; - case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING: - errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float"; - valueInt = (int)pParams[opIndex + 1]; - valueFloat = (float)pParams[opIndex + 2]; - GetAxisRange(valueInt, out axisLow, out axisHigh); - for (int ii = axisLow; ii <= axisHigh; ii++) - linkInfo.springDamping[ii] = valueFloat; - opIndex += 3; - break; - case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS: - errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float"; - valueInt = (int)pParams[opIndex + 1]; - valueFloat = (float)pParams[opIndex + 2]; - GetAxisRange(valueInt, out axisLow, out axisHigh); - for (int ii = axisLow; ii <= axisHigh; ii++) - linkInfo.springStiffness[ii] = valueFloat; - opIndex += 3; - break; - case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT: - errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector"; - valueVector = (OMV.Vector3)pParams[opIndex + 1]; - valueVector2 = (OMV.Vector3)pParams[opIndex + 2]; - linkInfo.springLinearEquilibriumPoint = valueVector; - linkInfo.springAngularEquilibriumPoint = valueVector2; - opIndex += 3; - break; - case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA: - errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)"; - valueBool = ((int)pParams[opIndex + 1]) != 0; - linkInfo.useLinearReferenceFrameA = valueBool; - opIndex += 2; - break; - default: - break; + thisOp = (int)pParams[opIndex]; + DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}", + linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]); + switch (thisOp) + { + case ExtendedPhysics.PHYS_PARAM_LINK_TYPE: + valueInt = (int)pParams[opIndex + 1]; + ConstraintType valueType = (ConstraintType)valueInt; + if (valueType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE + || valueType == ConstraintType.D6_CONSTRAINT_TYPE + || valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE + || valueType == ConstraintType.HINGE_CONSTRAINT_TYPE + || valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE + || valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE) + { + linkInfo.constraintType = valueType; + } + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC: + errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + linkInfo.frameInAloc = valueVector; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT: + errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation"; + valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; + linkInfo.frameInArot = valueQuaternion; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC: + errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + linkInfo.frameInBloc = valueVector; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT: + errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation"; + valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; + linkInfo.frameInBrot = valueQuaternion; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW: + errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + linkInfo.linearLimitLow = valueVector; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH: + errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + linkInfo.linearLimitHigh = valueVector; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW: + errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + linkInfo.angularLimitLow = valueVector; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH: + errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + linkInfo.angularLimitHigh = valueVector; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET: + errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)"; + valueBool = ((int)pParams[opIndex + 1]) != 0; + linkInfo.useFrameOffset = valueBool; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR: + errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)"; + valueBool = ((int)pParams[opIndex + 1]) != 0; + linkInfo.enableTransMotor = valueBool; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL: + errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float"; + valueFloat = (float)pParams[opIndex + 1]; + linkInfo.transMotorMaxVel = valueFloat; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE: + errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float"; + valueFloat = (float)pParams[opIndex + 1]; + linkInfo.transMotorMaxForce = valueFloat; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_CFM: + errMsg = "PHYS_PARAM_CFM takes one parameter of type float"; + valueFloat = (float)pParams[opIndex + 1]; + linkInfo.cfm = valueFloat; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_ERP: + errMsg = "PHYS_PARAM_ERP takes one parameter of type float"; + valueFloat = (float)pParams[opIndex + 1]; + linkInfo.erp = valueFloat; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS: + errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float"; + valueFloat = (float)pParams[opIndex + 1]; + linkInfo.solverIterations = valueFloat; + opIndex += 2; + break; + case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE: + errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)"; + valueInt = (int)pParams[opIndex + 1]; + valueBool = ((int)pParams[opIndex + 2]) != 0; + GetAxisRange(valueInt, out axisLow, out axisHigh); + for (int ii = axisLow; ii <= axisHigh; ii++) + linkInfo.springAxisEnable[ii] = valueBool; + opIndex += 3; + break; + case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING: + errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float"; + valueInt = (int)pParams[opIndex + 1]; + valueFloat = (float)pParams[opIndex + 2]; + GetAxisRange(valueInt, out axisLow, out axisHigh); + for (int ii = axisLow; ii <= axisHigh; ii++) + linkInfo.springDamping[ii] = valueFloat; + opIndex += 3; + break; + case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS: + errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float"; + valueInt = (int)pParams[opIndex + 1]; + valueFloat = (float)pParams[opIndex + 2]; + GetAxisRange(valueInt, out axisLow, out axisHigh); + for (int ii = axisLow; ii <= axisHigh; ii++) + linkInfo.springStiffness[ii] = valueFloat; + opIndex += 3; + break; + case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT: + errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector"; + valueVector = (OMV.Vector3)pParams[opIndex + 1]; + valueVector2 = (OMV.Vector3)pParams[opIndex + 2]; + linkInfo.springLinearEquilibriumPoint = valueVector; + linkInfo.springAngularEquilibriumPoint = valueVector2; + opIndex += 3; + break; + case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA: + errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)"; + valueBool = ((int)pParams[opIndex + 1]) != 0; + linkInfo.useLinearReferenceFrameA = valueBool; + opIndex += 2; + break; + default: + break; + } + } + catch (InvalidCastException e) + { + m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}", + LogHeader, errMsg, e); + } + catch (Exception e) + { + m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e); } } - catch (InvalidCastException e) - { - m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}", - LogHeader, errMsg, e); - } - catch (Exception e) - { - m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e); - } } + // Something changed so a rebuild is in order + Refresh(child); } - // Something changed so a rebuild is in order - Refresh(child); } - } - break; - default: - ret = base.Extension(pFunct, pParams); break; + default: + ret = base.Extension(pFunct, pParams); + break; + } + return ret; } - return ret; - } - // Bullet constraints keep some limit parameters for each linear and angular axis. - // Setting same is easier if there is an easy way to see all or types. - // This routine returns the array limits for the set of axis. - private void GetAxisRange(int rangeSpec, out int low, out int high) - { - switch (rangeSpec) + // Bullet constraints keep some limit parameters for each linear and angular axis. + // Setting same is easier if there is an easy way to see all or types. + // This routine returns the array limits for the set of axis. + private void GetAxisRange(int rangeSpec, out int low, out int high) { - case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL: - low = 0; - high = 2; - break; - case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL: - low = 3; - high = 5; - break; - case ExtendedPhysics.PHYS_AXIS_ALL: - low = 0; - high = 5; - break; - default: - low = high = rangeSpec; - break; + switch (rangeSpec) + { + case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL: + low = 0; + high = 2; + break; + case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL: + low = 3; + high = 5; + break; + case ExtendedPhysics.PHYS_AXIS_ALL: + low = 0; + high = 5; + break; + default: + low = high = rangeSpec; + break; + } + return; } - return; + #endregion // Extension } - #endregion // Extension - -} } diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs index 0e44d03770..ac27d91623 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSMaterials.cs @@ -32,172 +32,171 @@ using Nini.Config; namespace OpenSim.Region.PhysicsModule.BulletS { - -public struct MaterialAttributes -{ - // Material type values that correspond with definitions for LSL - public enum Material : int + public struct MaterialAttributes { - Stone = 0, - Metal, - Glass, - Wood, - Flesh, - Plastic, - Rubber, - Light, - // Hereafter are BulletSim additions - Avatar, - NumberOfTypes // the count of types in the enum. - } - - // Names must be in the order of the above enum. - // These names must coorespond to the lower case field names in the MaterialAttributes - // structure as reflection is used to select the field to put the value in. - public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"}; - - public MaterialAttributes(string t, float d, float f, float r) - { - type = t; - density = d; - friction = f; - restitution = r; - } - public string type; - public float density; - public float friction; - public float restitution; -} - -public static class BSMaterials -{ - // Attributes for each material type - private static readonly MaterialAttributes[] Attributes; - - // Map of material name to material type code - public static readonly Dictionary MaterialMap; - - static BSMaterials() - { - // Attribute sets for both the non-physical and physical instances of materials. - Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; - - // Map of name to type code. - MaterialMap = new Dictionary(); - MaterialMap.Add("Stone", MaterialAttributes.Material.Stone); - MaterialMap.Add("Metal", MaterialAttributes.Material.Metal); - MaterialMap.Add("Glass", MaterialAttributes.Material.Glass); - MaterialMap.Add("Wood", MaterialAttributes.Material.Wood); - MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh); - MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic); - MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber); - MaterialMap.Add("Light", MaterialAttributes.Material.Light); - MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar); - } - - // This is where all the default material attributes are defined. - public static void InitializeFromDefaults(ConfigurationParameters parms) - { - // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL - float dDensity = parms.defaultDensity; - float dFriction = parms.defaultFriction; - float dRestitution = parms.defaultRestitution; - Attributes[(int)MaterialAttributes.Material.Stone] = - new MaterialAttributes("stone",dDensity, 0.8f, 0.4f); - Attributes[(int)MaterialAttributes.Material.Metal] = - new MaterialAttributes("metal",dDensity, 0.3f, 0.4f); - Attributes[(int)MaterialAttributes.Material.Glass] = - new MaterialAttributes("glass",dDensity, 0.2f, 0.7f); - Attributes[(int)MaterialAttributes.Material.Wood] = - new MaterialAttributes("wood",dDensity, 0.6f, 0.5f); - Attributes[(int)MaterialAttributes.Material.Flesh] = - new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f); - Attributes[(int)MaterialAttributes.Material.Plastic] = - new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f); - Attributes[(int)MaterialAttributes.Material.Rubber] = - new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f); - Attributes[(int)MaterialAttributes.Material.Light] = - new MaterialAttributes("light",dDensity, dFriction, dRestitution); - Attributes[(int)MaterialAttributes.Material.Avatar] = - new MaterialAttributes("avatar",3.5f, 0.2f, 0f); - - Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f); - Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("metalPhysical",dDensity, 0.3f, 0.4f); - Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f); - Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f); - Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f); - Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f); - Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 0.9f); - Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution); - Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = - new MaterialAttributes("avatarPhysical",3.5f, 0.2f, 0f); - } - - // Under the [BulletSim] section, one can change the individual material - // attribute values. The format of the configuration parameter is: - // ["Physical"] = floatValue - // For instance: - // [BulletSim] - // StoneFriction = 0.2 - // FleshRestitutionPhysical = 0.8 - // Materials can have different parameters for their static and - // physical instantiations. When setting the non-physical value, - // both values are changed. Setting the physical value only changes - // the physical value. - public static void InitializefromParameters(IConfig pConfig) - { - foreach (KeyValuePair kvp in MaterialMap) + // Material type values that correspond with definitions for LSL + public enum Material : int { - string matName = kvp.Key; - foreach (string attribName in MaterialAttributes.MaterialAttribs) + Stone = 0, + Metal, + Glass, + Wood, + Flesh, + Plastic, + Rubber, + Light, + // Hereafter are BulletSim additions + Avatar, + NumberOfTypes // the count of types in the enum. + } + + // Names must be in the order of the above enum. + // These names must coorespond to the lower case field names in the MaterialAttributes + // structure as reflection is used to select the field to put the value in. + public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"}; + + public MaterialAttributes(string t, float d, float f, float r) + { + type = t; + density = d; + friction = f; + restitution = r; + } + public string type; + public float density; + public float friction; + public float restitution; + } + + public static class BSMaterials + { + // Attributes for each material type + private static readonly MaterialAttributes[] Attributes; + + // Map of material name to material type code + public static readonly Dictionary MaterialMap; + + static BSMaterials() + { + // Attribute sets for both the non-physical and physical instances of materials. + Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; + + // Map of name to type code. + MaterialMap = new Dictionary(); + MaterialMap.Add("Stone", MaterialAttributes.Material.Stone); + MaterialMap.Add("Metal", MaterialAttributes.Material.Metal); + MaterialMap.Add("Glass", MaterialAttributes.Material.Glass); + MaterialMap.Add("Wood", MaterialAttributes.Material.Wood); + MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh); + MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic); + MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber); + MaterialMap.Add("Light", MaterialAttributes.Material.Light); + MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar); + } + + // This is where all the default material attributes are defined. + public static void InitializeFromDefaults(ConfigurationParameters parms) + { + // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL + float dDensity = parms.defaultDensity; + float dFriction = parms.defaultFriction; + float dRestitution = parms.defaultRestitution; + Attributes[(int)MaterialAttributes.Material.Stone] = + new MaterialAttributes("stone",dDensity, 0.8f, 0.4f); + Attributes[(int)MaterialAttributes.Material.Metal] = + new MaterialAttributes("metal",dDensity, 0.3f, 0.4f); + Attributes[(int)MaterialAttributes.Material.Glass] = + new MaterialAttributes("glass",dDensity, 0.2f, 0.7f); + Attributes[(int)MaterialAttributes.Material.Wood] = + new MaterialAttributes("wood",dDensity, 0.6f, 0.5f); + Attributes[(int)MaterialAttributes.Material.Flesh] = + new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f); + Attributes[(int)MaterialAttributes.Material.Plastic] = + new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f); + Attributes[(int)MaterialAttributes.Material.Rubber] = + new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f); + Attributes[(int)MaterialAttributes.Material.Light] = + new MaterialAttributes("light",dDensity, dFriction, dRestitution); + Attributes[(int)MaterialAttributes.Material.Avatar] = + new MaterialAttributes("avatar",3.5f, 0.2f, 0f); + + Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f); + Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("metalPhysical",dDensity, 0.3f, 0.4f); + Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f); + Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f); + Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f); + Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f); + Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 0.9f); + Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution); + Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("avatarPhysical",3.5f, 0.2f, 0f); + } + + // Under the [BulletSim] section, one can change the individual material + // attribute values. The format of the configuration parameter is: + // ["Physical"] = floatValue + // For instance: + // [BulletSim] + // StoneFriction = 0.2 + // FleshRestitutionPhysical = 0.8 + // Materials can have different parameters for their static and + // physical instantiations. When setting the non-physical value, + // both values are changed. Setting the physical value only changes + // the physical value. + public static void InitializefromParameters(IConfig pConfig) + { + foreach (KeyValuePair kvp in MaterialMap) { - string paramName = matName + attribName; - if (pConfig.Contains(paramName)) + string matName = kvp.Key; + foreach (string attribName in MaterialAttributes.MaterialAttribs) { - float paramValue = pConfig.GetFloat(paramName); - SetAttributeValue((int)kvp.Value, attribName, paramValue); - // set the physical value also - SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); - } - paramName += "Physical"; - if (pConfig.Contains(paramName)) - { - float paramValue = pConfig.GetFloat(paramName); - SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); + string paramName = matName + attribName; + if (pConfig.Contains(paramName)) + { + float paramValue = pConfig.GetFloat(paramName); + SetAttributeValue((int)kvp.Value, attribName, paramValue); + // set the physical value also + SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); + } + paramName += "Physical"; + if (pConfig.Contains(paramName)) + { + float paramValue = pConfig.GetFloat(paramName); + SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); + } } } } - } - // Use reflection to set the value in the attribute structure. - private static void SetAttributeValue(int matType, string attribName, float val) - { - // Get the current attribute values for this material - MaterialAttributes thisAttrib = Attributes[matType]; - // Find the field for the passed attribute name (eg, find field named 'friction') - FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); - if (fieldInfo != null) + // Use reflection to set the value in the attribute structure. + private static void SetAttributeValue(int matType, string attribName, float val) { - fieldInfo.SetValue(thisAttrib, val); - // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference. - Attributes[matType] = thisAttrib; + // Get the current attribute values for this material + MaterialAttributes thisAttrib = Attributes[matType]; + // Find the field for the passed attribute name (eg, find field named 'friction') + FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); + if (fieldInfo != null) + { + fieldInfo.SetValue(thisAttrib, val); + // Copy new attributes back to array -- since MaterialAttributes is 'struct', passed by value, not reference. + Attributes[matType] = thisAttrib; + } + } + + // Given a material type, return a structure of attributes. + public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) + { + int ind = (int)type; + if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; + return Attributes[ind]; } } - - // Given a material type, return a structure of attributes. - public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) - { - int ind = (int)type; - if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; - return Attributes[ind]; - } -} } diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs index 2faf2d4c0c..a0a0b828bd 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSMotors.cs @@ -33,419 +33,419 @@ using OpenSim.Framework; namespace OpenSim.Region.PhysicsModule.BulletS { -public abstract class BSMotor -{ - // Timescales and other things can be turned off by setting them to 'infinite'. - public const float Infinite = 12345.6f; - public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); - - public BSMotor(string useName) + public abstract class BSMotor { - UseName = useName; - PhysicsScene = null; - Enabled = true; - } - public virtual bool Enabled { get; set; } - public virtual void Reset() { } - public virtual void Zero() { } - public virtual void GenerateTestOutput(float timeStep) { } + // Timescales and other things can be turned off by setting them to 'infinite'. + public const float Infinite = 12345.6f; + public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); - // A name passed at motor creation for easily identifyable debugging messages. - public string UseName { get; private set; } - - // Used only for outputting debug information. Might not be set so check for null. - public BSScene PhysicsScene { get; set; } - protected void MDetailLog(string msg, params Object[] parms) - { - if (PhysicsScene != null) + public BSMotor(string useName) { - PhysicsScene.DetailLog(msg, parms); + UseName = useName; + PhysicsScene = null; + Enabled = true; } - } -} + public virtual bool Enabled { get; set; } + public virtual void Reset() { } + public virtual void Zero() { } + public virtual void GenerateTestOutput(float timeStep) { } -// Motor which moves CurrentValue to TargetValue over TimeScale seconds. -// The TargetValue decays in TargetValueDecayTimeScale. -// This motor will "zero itself" over time in that the targetValue will -// decay to zero and the currentValue will follow it to that zero. -// The overall effect is for the returned correction value to go from large -// values to small and eventually zero values. -// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. + // A name passed at motor creation for easily identifyable debugging messages. + public string UseName { get; private set; } -// For instance, if something is moving at speed X and the desired speed is Y, -// CurrentValue is X and TargetValue is Y. As the motor is stepped, new -// values of CurrentValue are returned that approach the TargetValue. -// The feature of decaying TargetValue is so vehicles will eventually -// come to a stop rather than run forever. This can be disabled by -// setting TargetValueDecayTimescale to 'infinite'. -// The change from CurrentValue to TargetValue is linear over TimeScale seconds. -public class BSVMotor : BSMotor -{ - // public Vector3 FrameOfReference { get; set; } - // public Vector3 Offset { get; set; } - - public virtual float TimeScale { get; set; } - public virtual float TargetValueDecayTimeScale { get; set; } - public virtual float Efficiency { get; set; } - - public virtual float ErrorZeroThreshold { get; set; } - - public virtual Vector3 TargetValue { get; protected set; } - public virtual Vector3 CurrentValue { get; protected set; } - public virtual Vector3 LastError { get; protected set; } - - public virtual bool ErrorIsZero() - { - return ErrorIsZero(LastError); - } - public virtual bool ErrorIsZero(Vector3 err) - { - return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)); - } - - public BSVMotor(string useName) - : base(useName) - { - TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; - Efficiency = 1f; - CurrentValue = TargetValue = Vector3.Zero; - ErrorZeroThreshold = 0.001f; - } - public BSVMotor(string useName, float timeScale, float decayTimeScale, float efficiency) - : this(useName) - { - TimeScale = timeScale; - TargetValueDecayTimeScale = decayTimeScale; - Efficiency = efficiency; - CurrentValue = TargetValue = Vector3.Zero; - } - public void SetCurrent(Vector3 current) - { - CurrentValue = current; - } - public void SetTarget(Vector3 target) - { - TargetValue = target; - } - public override void Zero() - { - base.Zero(); - CurrentValue = TargetValue = Vector3.Zero; - } - - // Compute the next step and return the new current value. - // Returns the correction needed to move 'current' to 'target'. - public virtual Vector3 Step(float timeStep) - { - if (!Enabled) return TargetValue; - - Vector3 origTarget = TargetValue; // DEBUG - Vector3 origCurrVal = CurrentValue; // DEBUG - - Vector3 correction = Vector3.Zero; - Vector3 error = TargetValue - CurrentValue; - if (!ErrorIsZero(error)) + // Used only for outputting debug information. Might not be set so check for null. + public BSScene PhysicsScene { get; set; } + protected void MDetailLog(string msg, params Object[] parms) { - correction = StepError(timeStep, error); - - CurrentValue += correction; - - // The desired value reduces to zero which also reduces the difference with current. - // If the decay time is infinite, don't decay at all. - float decayFactor = 0f; - if (TargetValueDecayTimeScale != BSMotor.Infinite) + if (PhysicsScene != null) { - decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; - TargetValue *= (1f - decayFactor); + PhysicsScene.DetailLog(msg, parms); } - - MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", - BSScene.DetailLogZero, UseName, origCurrVal, origTarget, - timeStep, error, correction); - MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", - BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); } - else + } + + // Motor which moves CurrentValue to TargetValue over TimeScale seconds. + // The TargetValue decays in TargetValueDecayTimeScale. + // This motor will "zero itself" over time in that the targetValue will + // decay to zero and the currentValue will follow it to that zero. + // The overall effect is for the returned correction value to go from large + // values to small and eventually zero values. + // TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay. + + // For instance, if something is moving at speed X and the desired speed is Y, + // CurrentValue is X and TargetValue is Y. As the motor is stepped, new + // values of CurrentValue are returned that approach the TargetValue. + // The feature of decaying TargetValue is so vehicles will eventually + // come to a stop rather than run forever. This can be disabled by + // setting TargetValueDecayTimescale to 'infinite'. + // The change from CurrentValue to TargetValue is linear over TimeScale seconds. + public class BSVMotor : BSMotor + { + // public Vector3 FrameOfReference { get; set; } + // public Vector3 Offset { get; set; } + + public virtual float TimeScale { get; set; } + public virtual float TargetValueDecayTimeScale { get; set; } + public virtual float Efficiency { get; set; } + + public virtual float ErrorZeroThreshold { get; set; } + + public virtual Vector3 TargetValue { get; protected set; } + public virtual Vector3 CurrentValue { get; protected set; } + public virtual Vector3 LastError { get; protected set; } + + public virtual bool ErrorIsZero() { - // Difference between what we have and target is small. Motor is done. - if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) + return ErrorIsZero(LastError); + } + public virtual bool ErrorIsZero(Vector3 err) + { + return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)); + } + + public BSVMotor(string useName) + : base(useName) + { + TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; + Efficiency = 1f; + CurrentValue = TargetValue = Vector3.Zero; + ErrorZeroThreshold = 0.001f; + } + public BSVMotor(string useName, float timeScale, float decayTimeScale, float efficiency) + : this(useName) + { + TimeScale = timeScale; + TargetValueDecayTimeScale = decayTimeScale; + Efficiency = efficiency; + CurrentValue = TargetValue = Vector3.Zero; + } + public void SetCurrent(Vector3 current) + { + CurrentValue = current; + } + public void SetTarget(Vector3 target) + { + TargetValue = target; + } + public override void Zero() + { + base.Zero(); + CurrentValue = TargetValue = Vector3.Zero; + } + + // Compute the next step and return the new current value. + // Returns the correction needed to move 'current' to 'target'. + public virtual Vector3 Step(float timeStep) + { + if (!Enabled) return TargetValue; + + Vector3 origTarget = TargetValue; // DEBUG + Vector3 origCurrVal = CurrentValue; // DEBUG + + Vector3 correction = Vector3.Zero; + Vector3 error = TargetValue - CurrentValue; + if (!ErrorIsZero(error)) { - // The target can step down to nearly zero but not get there. If close to zero - // it is really zero. - TargetValue = Vector3.Zero; + correction = StepError(timeStep, error); + + CurrentValue += correction; + + // The desired value reduces to zero which also reduces the difference with current. + // If the decay time is infinite, don't decay at all. + float decayFactor = 0f; + if (TargetValueDecayTimeScale != BSMotor.Infinite) + { + decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; + TargetValue *= (1f - decayFactor); + } + + MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", + BSScene.DetailLogZero, UseName, origCurrVal, origTarget, + timeStep, error, correction); + MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", + BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); } - CurrentValue = TargetValue; - MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}", - BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue); - } - LastError = error; - - return correction; - } - // version of step that sets the current value before doing the step - public virtual Vector3 Step(float timeStep, Vector3 current) - { - CurrentValue = current; - return Step(timeStep); - } - // Given and error, computer a correction for this step. - // Simple scaling of the error by the timestep. - public virtual Vector3 StepError(float timeStep, Vector3 error) - { - if (!Enabled) return Vector3.Zero; - - Vector3 returnCorrection = Vector3.Zero; - if (!ErrorIsZero(error)) - { - // correction = error / secondsItShouldTakeToCorrect - Vector3 correctionAmount; - if (TimeScale == 0f || TimeScale == BSMotor.Infinite) - correctionAmount = error * timeStep; else - correctionAmount = error / TimeScale * timeStep; - - returnCorrection = correctionAmount; - MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", - BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); - } - return returnCorrection; - } - - // The user sets all the parameters and calls this which outputs values until error is zero. - public override void GenerateTestOutput(float timeStep) - { - // maximum number of outputs to generate. - int maxOutput = 50; - MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); - MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}", - BSScene.DetailLogZero, UseName, - TimeScale, TargetValueDecayTimeScale, Efficiency, - CurrentValue, TargetValue); - - LastError = BSMotor.InfiniteVector; - while (maxOutput-- > 0 && !ErrorIsZero()) - { - Vector3 lastStep = Step(timeStep); - MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}", - BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); - } - MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); - - - } - - public override string ToString() - { - return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", - UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); - } -} - -// ============================================================================ -// ============================================================================ -public class BSFMotor : BSMotor -{ - public virtual float TimeScale { get; set; } - public virtual float TargetValueDecayTimeScale { get; set; } - public virtual float Efficiency { get; set; } - - public virtual float ErrorZeroThreshold { get; set; } - - public virtual float TargetValue { get; protected set; } - public virtual float CurrentValue { get; protected set; } - public virtual float LastError { get; protected set; } - - public virtual bool ErrorIsZero() - { - return ErrorIsZero(LastError); - } - public virtual bool ErrorIsZero(float err) - { - return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); - } - - public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency) - : base(useName) - { - TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; - Efficiency = 1f; - CurrentValue = TargetValue = 0f; - ErrorZeroThreshold = 0.01f; - } - public void SetCurrent(float current) - { - CurrentValue = current; - } - public void SetTarget(float target) - { - TargetValue = target; - } - public override void Zero() - { - base.Zero(); - CurrentValue = TargetValue = 0f; - } - - public virtual float Step(float timeStep) - { - if (!Enabled) return TargetValue; - - float origTarget = TargetValue; // DEBUG - float origCurrVal = CurrentValue; // DEBUG - - float correction = 0f; - float error = TargetValue - CurrentValue; - if (!ErrorIsZero(error)) - { - correction = StepError(timeStep, error); - - CurrentValue += correction; - - // The desired value reduces to zero which also reduces the difference with current. - // If the decay time is infinite, don't decay at all. - float decayFactor = 0f; - if (TargetValueDecayTimeScale != BSMotor.Infinite) { - decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; - TargetValue *= (1f - decayFactor); + // Difference between what we have and target is small. Motor is done. + if (TargetValue.ApproxEquals(Vector3.Zero, ErrorZeroThreshold)) + { + // The target can step down to nearly zero but not get there. If close to zero + // it is really zero. + TargetValue = Vector3.Zero; + } + CurrentValue = TargetValue; + MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},currTgt={4},currCurr={5}", + BSScene.DetailLogZero, UseName, origCurrVal, origTarget, TargetValue, CurrentValue); } + LastError = error; - MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", - BSScene.DetailLogZero, UseName, origCurrVal, origTarget, - timeStep, error, correction); - MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", - BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); + return correction; } - else + // version of step that sets the current value before doing the step + public virtual Vector3 Step(float timeStep, Vector3 current) { - // Difference between what we have and target is small. Motor is done. - if (Util.InRange(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold)) - { - // The target can step down to nearly zero but not get there. If close to zero - // it is really zero. - TargetValue = 0f; - } - CurrentValue = TargetValue; - MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", - BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); + CurrentValue = current; + return Step(timeStep); } - LastError = error; + // Given and error, computer a correction for this step. + // Simple scaling of the error by the timestep. + public virtual Vector3 StepError(float timeStep, Vector3 error) + { + if (!Enabled) return Vector3.Zero; - return CurrentValue; + Vector3 returnCorrection = Vector3.Zero; + if (!ErrorIsZero(error)) + { + // correction = error / secondsItShouldTakeToCorrect + Vector3 correctionAmount; + if (TimeScale == 0f || TimeScale == BSMotor.Infinite) + correctionAmount = error * timeStep; + else + correctionAmount = error / TimeScale * timeStep; + + returnCorrection = correctionAmount; + MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", + BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); + } + return returnCorrection; + } + + // The user sets all the parameters and calls this which outputs values until error is zero. + public override void GenerateTestOutput(float timeStep) + { + // maximum number of outputs to generate. + int maxOutput = 50; + MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName); + MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},eff={4},curr={5},tgt={6}", + BSScene.DetailLogZero, UseName, + TimeScale, TargetValueDecayTimeScale, Efficiency, + CurrentValue, TargetValue); + + LastError = BSMotor.InfiniteVector; + while (maxOutput-- > 0 && !ErrorIsZero()) + { + Vector3 lastStep = Step(timeStep); + MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}", + BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep); + } + MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName); + + + } + + public override string ToString() + { + return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", + UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); + } } - public virtual float StepError(float timeStep, float error) + // ============================================================================ + // ============================================================================ + public class BSFMotor : BSMotor { - if (!Enabled) return 0f; + public virtual float TimeScale { get; set; } + public virtual float TargetValueDecayTimeScale { get; set; } + public virtual float Efficiency { get; set; } - float returnCorrection = 0f; - if (!ErrorIsZero(error)) + public virtual float ErrorZeroThreshold { get; set; } + + public virtual float TargetValue { get; protected set; } + public virtual float CurrentValue { get; protected set; } + public virtual float LastError { get; protected set; } + + public virtual bool ErrorIsZero() { - // correction = error / secondsItShouldTakeToCorrect - float correctionAmount; - if (TimeScale == 0f || TimeScale == BSMotor.Infinite) - correctionAmount = error * timeStep; + return ErrorIsZero(LastError); + } + public virtual bool ErrorIsZero(float err) + { + return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold); + } + + public BSFMotor(string useName, float timeScale, float decayTimescale, float efficiency) + : base(useName) + { + TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; + Efficiency = 1f; + CurrentValue = TargetValue = 0f; + ErrorZeroThreshold = 0.01f; + } + public void SetCurrent(float current) + { + CurrentValue = current; + } + public void SetTarget(float target) + { + TargetValue = target; + } + public override void Zero() + { + base.Zero(); + CurrentValue = TargetValue = 0f; + } + + public virtual float Step(float timeStep) + { + if (!Enabled) return TargetValue; + + float origTarget = TargetValue; // DEBUG + float origCurrVal = CurrentValue; // DEBUG + + float correction = 0f; + float error = TargetValue - CurrentValue; + if (!ErrorIsZero(error)) + { + correction = StepError(timeStep, error); + + CurrentValue += correction; + + // The desired value reduces to zero which also reduces the difference with current. + // If the decay time is infinite, don't decay at all. + float decayFactor = 0f; + if (TargetValueDecayTimeScale != BSMotor.Infinite) + { + decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; + TargetValue *= (1f - decayFactor); + } + + MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}", + BSScene.DetailLogZero, UseName, origCurrVal, origTarget, + timeStep, error, correction); + MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},tgt={4},curr={5}", + BSScene.DetailLogZero, UseName, TargetValueDecayTimeScale, decayFactor, TargetValue, CurrentValue); + } else - correctionAmount = error / TimeScale * timeStep; + { + // Difference between what we have and target is small. Motor is done. + if (Util.InRange(TargetValue, -ErrorZeroThreshold, ErrorZeroThreshold)) + { + // The target can step down to nearly zero but not get there. If close to zero + // it is really zero. + TargetValue = 0f; + } + CurrentValue = TargetValue; + MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}", + BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue); + } + LastError = error; - returnCorrection = correctionAmount; - MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", - BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); + return CurrentValue; } - return returnCorrection; - } - public override string ToString() - { - return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", - UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); - } - -} - -// ============================================================================ -// ============================================================================ -// Proportional, Integral, Derivitive ("PID") Motor -// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. -public class BSPIDVMotor : BSVMotor -{ - // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10. - public Vector3 proportionFactor { get; set; } - public Vector3 integralFactor { get; set; } - public Vector3 derivFactor { get; set; } - - // The factors are vectors for the three dimensions. This is the proportional of each - // that is applied. This could be multiplied through the actual factors but it - // is sometimes easier to manipulate the factors and their mix separately. - public Vector3 FactorMix; - - // Arbritrary factor range. - // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. - public float EfficiencyHigh = 0.4f; - public float EfficiencyLow = 4.0f; - - // Running integration of the error - Vector3 RunningIntegration { get; set; } - - public BSPIDVMotor(string useName) - : base(useName) - { - proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); - integralFactor = new Vector3(1.00f, 1.00f, 1.00f); - derivFactor = new Vector3(1.00f, 1.00f, 1.00f); - FactorMix = new Vector3(0.5f, 0.25f, 0.25f); - RunningIntegration = Vector3.Zero; - LastError = Vector3.Zero; - } - - public override void Zero() - { - base.Zero(); - } - - public override float Efficiency - { - get { return base.Efficiency; } - set + public virtual float StepError(float timeStep, float error) { - base.Efficiency = Util.Clamp(value, 0f, 1f); + if (!Enabled) return 0f; - // Compute factors based on efficiency. - // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. - // If efficiency is low (0f), use a factor value that overcorrects. - // TODO: might want to vary contribution of different factor depending on efficiency. - // float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; - float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; + float returnCorrection = 0f; + if (!ErrorIsZero(error)) + { + // correction = error / secondsItShouldTakeToCorrect + float correctionAmount; + if (TimeScale == 0f || TimeScale == BSMotor.Infinite) + correctionAmount = error * timeStep; + else + correctionAmount = error / TimeScale * timeStep; - proportionFactor = new Vector3(factor, factor, factor); - integralFactor = new Vector3(factor, factor, factor); - derivFactor = new Vector3(factor, factor, factor); + returnCorrection = correctionAmount; + MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}", + BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount); + } + return returnCorrection; + } - MDetailLog("{0}, BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor); + public override string ToString() + { + return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4}>", + UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale); + } + + } + + // ============================================================================ + // ============================================================================ + // Proportional, Integral, Derivitive ("PID") Motor + // Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors. + public class BSPIDVMotor : BSVMotor + { + // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10. + public Vector3 proportionFactor { get; set; } + public Vector3 integralFactor { get; set; } + public Vector3 derivFactor { get; set; } + + // The factors are vectors for the three dimensions. This is the proportional of each + // that is applied. This could be multiplied through the actual factors but it + // is sometimes easier to manipulate the factors and their mix separately. + public Vector3 FactorMix; + + // Arbritrary factor range. + // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct. + public float EfficiencyHigh = 0.4f; + public float EfficiencyLow = 4.0f; + + // Running integration of the error + Vector3 RunningIntegration { get; set; } + + public BSPIDVMotor(string useName) + : base(useName) + { + proportionFactor = new Vector3(1.00f, 1.00f, 1.00f); + integralFactor = new Vector3(1.00f, 1.00f, 1.00f); + derivFactor = new Vector3(1.00f, 1.00f, 1.00f); + FactorMix = new Vector3(0.5f, 0.25f, 0.25f); + RunningIntegration = Vector3.Zero; + LastError = Vector3.Zero; + } + + public override void Zero() + { + base.Zero(); + } + + public override float Efficiency + { + get { return base.Efficiency; } + set + { + base.Efficiency = Util.Clamp(value, 0f, 1f); + + // Compute factors based on efficiency. + // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot. + // If efficiency is low (0f), use a factor value that overcorrects. + // TODO: might want to vary contribution of different factor depending on efficiency. + // float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f; + float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow; + + proportionFactor = new Vector3(factor, factor, factor); + integralFactor = new Vector3(factor, factor, factor); + derivFactor = new Vector3(factor, factor, factor); + + MDetailLog("{0}, BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor); + } + } + + // Advance the PID computation on this error. + public override Vector3 StepError(float timeStep, Vector3 error) + { + if (!Enabled) return Vector3.Zero; + + // Add up the error so we can integrate over the accumulated errors + RunningIntegration += error * timeStep; + + // A simple derivitive is the rate of change from the last error. + Vector3 derivitive = (error - LastError) * timeStep; + + // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) + Vector3 ret = error / TimeScale * timeStep * proportionFactor * FactorMix.X + + RunningIntegration / TimeScale * integralFactor * FactorMix.Y + + derivitive / TimeScale * derivFactor * FactorMix.Z + ; + + MDetailLog("{0}, BSPIDVMotor.step,ts={1},err={2},lerr={3},runnInt={4},deriv={5},ret={6}", + BSScene.DetailLogZero, timeStep, error, LastError, RunningIntegration, derivitive, ret); + + return ret; } } - - // Advance the PID computation on this error. - public override Vector3 StepError(float timeStep, Vector3 error) - { - if (!Enabled) return Vector3.Zero; - - // Add up the error so we can integrate over the accumulated errors - RunningIntegration += error * timeStep; - - // A simple derivitive is the rate of change from the last error. - Vector3 derivitive = (error - LastError) * timeStep; - - // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError) - Vector3 ret = error / TimeScale * timeStep * proportionFactor * FactorMix.X - + RunningIntegration / TimeScale * integralFactor * FactorMix.Y - + derivitive / TimeScale * derivFactor * FactorMix.Z - ; - - MDetailLog("{0}, BSPIDVMotor.step,ts={1},err={2},lerr={3},runnInt={4},deriv={5},ret={6}", - BSScene.DetailLogZero, timeStep, error, LastError, RunningIntegration, derivitive, ret); - - return ret; - } -} } diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs index d80b050de6..13192b0353 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSParam.cs @@ -36,917 +36,917 @@ using Nini.Config; namespace OpenSim.Region.PhysicsModule.BulletS { -public static class BSParam -{ - private static string LogHeader = "[BULLETSIM PARAMETERS]"; - - // Tuning notes: - // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575 - // Contact points can be added even if the distance is positive. The constraint solver can deal with - // contacts with positive distances as well as negative (penetration). Contact points are discarded - // if the distance exceeds a certain threshold. - // Bullet has a contact processing threshold and a contact breaking threshold. - // If the distance is larger than the contact breaking threshold, it will be removed after one frame. - // If the distance is larger than the contact processing threshold, the constraint solver will ignore it. - - // This is separate/independent from the collision margin. The collision margin increases the object a bit - // to improve collision detection performance and accuracy. - // =================== - // From: - - /// - /// Set whether physics is active or not. - /// - /// - /// Can be enabled and disabled to start and stop physics. - /// - public static bool Active { get; private set; } - - public static bool UseSeparatePhysicsThread { get; private set; } - public static float PhysicsTimeStep { get; private set; } - - // Level of Detail values kept as float because that's what the Meshmerizer wants - public static float MeshLOD { get; private set; } - public static float MeshCircularLOD { get; private set; } - public static float MeshMegaPrimLOD { get; private set; } - public static float MeshMegaPrimThreshold { get; private set; } - public static float SculptLOD { get; private set; } - - public static int CrossingFailuresBeforeOutOfBounds { get; private set; } - public static float UpdateVelocityChangeThreshold { get; private set; } - - public static float MinimumObjectMass { get; private set; } - public static float MaximumObjectMass { get; private set; } - public static float MaxLinearVelocity { get; private set; } - public static float MaxLinearVelocitySquared { get; private set; } - public static float MaxAngularVelocity { get; private set; } - public static float MaxAngularVelocitySquared { get; private set; } - public static float MaxAddForceMagnitude { get; private set; } - public static float MaxAddForceMagnitudeSquared { get; private set; } - public static float DensityScaleFactor { get; private set; } - - public static float LinearDamping { get; private set; } - public static float AngularDamping { get; private set; } - public static float DeactivationTime { get; private set; } - public static float LinearSleepingThreshold { get; private set; } - public static float AngularSleepingThreshold { get; private set; } - public static float CcdMotionThreshold { get; private set; } - public static float CcdSweptSphereRadius { get; private set; } - public static float ContactProcessingThreshold { get; private set; } - - public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed - public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes - public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects - public static bool ShouldRemoveZeroWidthTriangles { get; private set; } - public static bool ShouldUseBulletHACD { get; set; } - public static bool ShouldUseSingleConvexHullForPrims { get; set; } - public static bool ShouldUseGImpactShapeForPrims { get; set; } - public static bool ShouldUseAssetHulls { get; set; } - - public static float TerrainImplementation { get; set; } - public static int TerrainMeshMagnification { get; private set; } - public static float TerrainGroundPlane { get; private set; } - public static float TerrainFriction { get; private set; } - public static float TerrainHitFraction { get; private set; } - public static float TerrainRestitution { get; private set; } - public static float TerrainContactProcessingThreshold { get; private set; } - public static float TerrainCollisionMargin { get; private set; } - - public static float DefaultFriction { get; private set; } - public static float DefaultDensity { get; private set; } - public static float DefaultRestitution { get; private set; } - public static float CollisionMargin { get; private set; } - public static float Gravity { get; private set; } - - // Physics Engine operation - public static float MaxPersistantManifoldPoolSize { get; private set; } - public static float MaxCollisionAlgorithmPoolSize { get; private set; } - public static bool ShouldDisableContactPoolDynamicAllocation { get; private set; } - public static bool ShouldForceUpdateAllAabbs { get; private set; } - public static bool ShouldRandomizeSolverOrder { get; private set; } - public static bool ShouldSplitSimulationIslands { get; private set; } - public static bool ShouldEnableFrictionCaching { get; private set; } - public static float NumberOfSolverIterations { get; private set; } - public static bool UseSingleSidedMeshes { get; private set; } - public static float GlobalContactBreakingThreshold { get; private set; } - public static float PhysicsUnmanLoggingFrames { get; private set; } - - // Avatar parameters - public static bool AvatarToAvatarCollisionsByDefault { get; private set; } - public static float AvatarFriction { get; private set; } - public static float AvatarStandingFriction { get; private set; } - public static float AvatarWalkVelocityFactor { get; private set; } - public static float AvatarAlwaysRunFactor { get; private set; } - public static float AvatarDensity { get; private set; } - public static float AvatarRestitution { get; private set; } - public static int AvatarShape { get; private set; } - public static float AvatarCapsuleWidth { get; private set; } - public static float AvatarCapsuleDepth { get; private set; } - public static float AvatarCapsuleHeight { get; private set; } - public static bool AvatarUseBefore09SizeComputation { get; private set; } - public static float AvatarHeightLowFudge { get; private set; } - public static float AvatarHeightMidFudge { get; private set; } - public static float AvatarHeightHighFudge { get; private set; } - public static float AvatarFlyingGroundMargin { get; private set; } - public static float AvatarFlyingGroundUpForce { get; private set; } - public static int AvatarAddForceFrames { get; private set; } - public static float AvatarTerminalVelocity { get; private set; } - public static float AvatarContactProcessingThreshold { get; private set; } - public static float AvatarAddForcePushFactor { get; private set; } - public static float AvatarStopZeroThreshold { get; private set; } - public static float AvatarStopZeroThresholdSquared { get; private set; } - public static int AvatarJumpFrames { get; private set; } - public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } - public static float AvatarStepHeight { get; private set; } - public static float AvatarStepAngle { get; private set; } - public static float AvatarStepGroundFudge { get; private set; } - public static float AvatarStepApproachFactor { get; private set; } - public static float AvatarStepForceFactor { get; private set; } - public static float AvatarStepUpCorrectionFactor { get; private set; } - public static int AvatarStepSmoothingSteps { get; private set; } - - // Vehicle parameters - public static float VehicleMaxLinearVelocity { get; private set; } - public static float VehicleMaxLinearVelocitySquared { get; private set; } - public static float VehicleMinLinearVelocity { get; private set; } - public static float VehicleMinLinearVelocitySquared { get; private set; } - public static float VehicleMaxAngularVelocity { get; private set; } - public static float VehicleMaxAngularVelocitySq { get; private set; } - public static float VehicleAngularDamping { get; private set; } - public static float VehicleFriction { get; private set; } - public static float VehicleRestitution { get; private set; } - public static Vector3 VehicleLinearFactor { get; private set; } - public static Vector3 VehicleAngularFactor { get; private set; } - public static Vector3 VehicleInertiaFactor { get; private set; } - public static float VehicleGroundGravityFudge { get; private set; } - public static float VehicleAngularBankingTimescaleFudge { get; private set; } - public static bool VehicleEnableLinearDeflection { get; private set; } - public static bool VehicleLinearDeflectionNotCollidingNoZ { get; private set; } - public static bool VehicleEnableAngularVerticalAttraction { get; private set; } - public static int VehicleAngularVerticalAttractionAlgorithm { get; private set; } - public static bool VehicleEnableAngularDeflection { get; private set; } - public static bool VehicleEnableAngularBanking { get; private set; } - - // Convex Hulls - // Parameters for convex hull routine that ships with Bullet - public static int CSHullMaxDepthSplit { get; private set; } - public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; } - public static float CSHullConcavityThresholdPercent { get; private set; } - public static float CSHullVolumeConservationThresholdPercent { get; private set; } - public static int CSHullMaxVertices { get; private set; } - public static float CSHullMaxSkinWidth { get; private set; } - public static float BHullMaxVerticesPerHull { get; private set; } // 100 - public static float BHullMinClusters { get; private set; } // 2 - public static float BHullCompacityWeight { get; private set; } // 0.1 - public static float BHullVolumeWeight { get; private set; } // 0.0 - public static float BHullConcavity { get; private set; } // 100 - public static bool BHullAddExtraDistPoints { get; private set; } // false - public static bool BHullAddNeighboursDistPoints { get; private set; } // false - public static bool BHullAddFacesPoints { get; private set; } // false - public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false - public static float WhichHACD { get; private set; } // zero if Bullet HACD, non-zero says VHACD - // Parameters for VHACD 2.0: http://code.google.com/p/v-hacd - // To enable, set both ShouldUseBulletHACD=true and WhichHACD=1 - // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html - public static float VHACDresolution { get; private set; } // 100,000 max number of voxels generated during voxelization stage - public static float VHACDdepth { get; private set; } // 20 max number of clipping stages - public static float VHACDconcavity { get; private set; } // 0.0025 maximum concavity - public static float VHACDplaneDownsampling { get; private set; } // 4 granularity of search for best clipping plane - public static float VHACDconvexHullDownsampling { get; private set; } // 4 precision of hull gen process - public static float VHACDalpha { get; private set; } // 0.05 bias toward clipping along symmetry planes - public static float VHACDbeta { get; private set; } // 0.05 bias toward clipping along revolution axis - public static float VHACDgamma { get; private set; } // 0.00125 max concavity when merging - public static float VHACDpca { get; private set; } // 0 on/off normalizing mesh before decomp - public static float VHACDmode { get; private set; } // 0 0:voxel based, 1: tetrahedron based - public static float VHACDmaxNumVerticesPerCH { get; private set; } // 64 max triangles per convex hull - public static float VHACDminVolumePerCH { get; private set; } // 0.0001 sampling of generated convex hulls - - // Linkset implementation parameters - public static float LinksetImplementation { get; private set; } - public static bool LinksetOffsetCenterOfMass { get; private set; } - public static bool LinkConstraintUseFrameOffset { get; private set; } - public static bool LinkConstraintEnableTransMotor { get; private set; } - public static float LinkConstraintTransMotorMaxVel { get; private set; } - public static float LinkConstraintTransMotorMaxForce { get; private set; } - public static float LinkConstraintERP { get; private set; } - public static float LinkConstraintCFM { get; private set; } - public static float LinkConstraintSolverIterations { get; private set; } - - public static bool UseBulletRaycast { get; private set; } - - public static float PID_D { get; private set; } // derivative - public static float PID_P { get; private set; } // proportional - - public static float DebugNumber { get; private set; } // A console setable number used for debugging - - // Various constants that come from that other virtual world that shall not be named. - public const float MinGravityZ = -1f; - public const float MaxGravityZ = 28f; - public const float MinFriction = 0f; - public const float MaxFriction = 255f; - public const float MinDensity = 0.01f; - public const float MaxDensity = 22587f; - public const float MinRestitution = 0f; - public const float MaxRestitution = 1f; - - // ===================================================================================== - // ===================================================================================== - - // Base parameter definition that gets and sets parameter values via a string - public abstract class ParameterDefnBase + public static class BSParam { - public string name; // string name of the parameter - public string desc; // a short description of what the parameter means - public ParameterDefnBase(string pName, string pDesc) - { - name = pName; - desc = pDesc; - } - // Set the parameter value to the default - public abstract void AssignDefault(BSScene s); - // Get the value as a string - public abstract string GetValue(BSScene s); - // Set the value to this string value - public abstract void SetValue(BSScene s, string valAsString); - // set the value on a particular object (usually sets in physics engine) - public abstract void SetOnObject(BSScene s, BSPhysObject obj); - public abstract bool HasSetOnObject { get; } - } + private static string LogHeader = "[BULLETSIM PARAMETERS]"; - // Specific parameter definition for a parameter of a specific type. - public delegate T PGetValue(BSScene s); - public delegate void PSetValue(BSScene s, T val); - public delegate void PSetOnObject(BSScene scene, BSPhysObject obj); - public sealed class ParameterDefn : ParameterDefnBase - { - private T defaultValue; - private PSetValue setter; - private PGetValue getter; - private PSetOnObject objectSet; - public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue pGetter, PSetValue pSetter) - : base(pName, pDesc) + // Tuning notes: + // From: http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6575 + // Contact points can be added even if the distance is positive. The constraint solver can deal with + // contacts with positive distances as well as negative (penetration). Contact points are discarded + // if the distance exceeds a certain threshold. + // Bullet has a contact processing threshold and a contact breaking threshold. + // If the distance is larger than the contact breaking threshold, it will be removed after one frame. + // If the distance is larger than the contact processing threshold, the constraint solver will ignore it. + + // This is separate/independent from the collision margin. The collision margin increases the object a bit + // to improve collision detection performance and accuracy. + // =================== + // From: + + /// + /// Set whether physics is active or not. + /// + /// + /// Can be enabled and disabled to start and stop physics. + /// + public static bool Active { get; private set; } + + public static bool UseSeparatePhysicsThread { get; private set; } + public static float PhysicsTimeStep { get; private set; } + + // Level of Detail values kept as float because that's what the Meshmerizer wants + public static float MeshLOD { get; private set; } + public static float MeshCircularLOD { get; private set; } + public static float MeshMegaPrimLOD { get; private set; } + public static float MeshMegaPrimThreshold { get; private set; } + public static float SculptLOD { get; private set; } + + public static int CrossingFailuresBeforeOutOfBounds { get; private set; } + public static float UpdateVelocityChangeThreshold { get; private set; } + + public static float MinimumObjectMass { get; private set; } + public static float MaximumObjectMass { get; private set; } + public static float MaxLinearVelocity { get; private set; } + public static float MaxLinearVelocitySquared { get; private set; } + public static float MaxAngularVelocity { get; private set; } + public static float MaxAngularVelocitySquared { get; private set; } + public static float MaxAddForceMagnitude { get; private set; } + public static float MaxAddForceMagnitudeSquared { get; private set; } + public static float DensityScaleFactor { get; private set; } + + public static float LinearDamping { get; private set; } + public static float AngularDamping { get; private set; } + public static float DeactivationTime { get; private set; } + public static float LinearSleepingThreshold { get; private set; } + public static float AngularSleepingThreshold { get; private set; } + public static float CcdMotionThreshold { get; private set; } + public static float CcdSweptSphereRadius { get; private set; } + public static float ContactProcessingThreshold { get; private set; } + + public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed + public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes + public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects + public static bool ShouldRemoveZeroWidthTriangles { get; private set; } + public static bool ShouldUseBulletHACD { get; set; } + public static bool ShouldUseSingleConvexHullForPrims { get; set; } + public static bool ShouldUseGImpactShapeForPrims { get; set; } + public static bool ShouldUseAssetHulls { get; set; } + + public static float TerrainImplementation { get; set; } + public static int TerrainMeshMagnification { get; private set; } + public static float TerrainGroundPlane { get; private set; } + public static float TerrainFriction { get; private set; } + public static float TerrainHitFraction { get; private set; } + public static float TerrainRestitution { get; private set; } + public static float TerrainContactProcessingThreshold { get; private set; } + public static float TerrainCollisionMargin { get; private set; } + + public static float DefaultFriction { get; private set; } + public static float DefaultDensity { get; private set; } + public static float DefaultRestitution { get; private set; } + public static float CollisionMargin { get; private set; } + public static float Gravity { get; private set; } + + // Physics Engine operation + public static float MaxPersistantManifoldPoolSize { get; private set; } + public static float MaxCollisionAlgorithmPoolSize { get; private set; } + public static bool ShouldDisableContactPoolDynamicAllocation { get; private set; } + public static bool ShouldForceUpdateAllAabbs { get; private set; } + public static bool ShouldRandomizeSolverOrder { get; private set; } + public static bool ShouldSplitSimulationIslands { get; private set; } + public static bool ShouldEnableFrictionCaching { get; private set; } + public static float NumberOfSolverIterations { get; private set; } + public static bool UseSingleSidedMeshes { get; private set; } + public static float GlobalContactBreakingThreshold { get; private set; } + public static float PhysicsUnmanLoggingFrames { get; private set; } + + // Avatar parameters + public static bool AvatarToAvatarCollisionsByDefault { get; private set; } + public static float AvatarFriction { get; private set; } + public static float AvatarStandingFriction { get; private set; } + public static float AvatarWalkVelocityFactor { get; private set; } + public static float AvatarAlwaysRunFactor { get; private set; } + public static float AvatarDensity { get; private set; } + public static float AvatarRestitution { get; private set; } + public static int AvatarShape { get; private set; } + public static float AvatarCapsuleWidth { get; private set; } + public static float AvatarCapsuleDepth { get; private set; } + public static float AvatarCapsuleHeight { get; private set; } + public static bool AvatarUseBefore09SizeComputation { get; private set; } + public static float AvatarHeightLowFudge { get; private set; } + public static float AvatarHeightMidFudge { get; private set; } + public static float AvatarHeightHighFudge { get; private set; } + public static float AvatarFlyingGroundMargin { get; private set; } + public static float AvatarFlyingGroundUpForce { get; private set; } + public static int AvatarAddForceFrames { get; private set; } + public static float AvatarTerminalVelocity { get; private set; } + public static float AvatarContactProcessingThreshold { get; private set; } + public static float AvatarAddForcePushFactor { get; private set; } + public static float AvatarStopZeroThreshold { get; private set; } + public static float AvatarStopZeroThresholdSquared { get; private set; } + public static int AvatarJumpFrames { get; private set; } + public static float AvatarBelowGroundUpCorrectionMeters { get; private set; } + public static float AvatarStepHeight { get; private set; } + public static float AvatarStepAngle { get; private set; } + public static float AvatarStepGroundFudge { get; private set; } + public static float AvatarStepApproachFactor { get; private set; } + public static float AvatarStepForceFactor { get; private set; } + public static float AvatarStepUpCorrectionFactor { get; private set; } + public static int AvatarStepSmoothingSteps { get; private set; } + + // Vehicle parameters + public static float VehicleMaxLinearVelocity { get; private set; } + public static float VehicleMaxLinearVelocitySquared { get; private set; } + public static float VehicleMinLinearVelocity { get; private set; } + public static float VehicleMinLinearVelocitySquared { get; private set; } + public static float VehicleMaxAngularVelocity { get; private set; } + public static float VehicleMaxAngularVelocitySq { get; private set; } + public static float VehicleAngularDamping { get; private set; } + public static float VehicleFriction { get; private set; } + public static float VehicleRestitution { get; private set; } + public static Vector3 VehicleLinearFactor { get; private set; } + public static Vector3 VehicleAngularFactor { get; private set; } + public static Vector3 VehicleInertiaFactor { get; private set; } + public static float VehicleGroundGravityFudge { get; private set; } + public static float VehicleAngularBankingTimescaleFudge { get; private set; } + public static bool VehicleEnableLinearDeflection { get; private set; } + public static bool VehicleLinearDeflectionNotCollidingNoZ { get; private set; } + public static bool VehicleEnableAngularVerticalAttraction { get; private set; } + public static int VehicleAngularVerticalAttractionAlgorithm { get; private set; } + public static bool VehicleEnableAngularDeflection { get; private set; } + public static bool VehicleEnableAngularBanking { get; private set; } + + // Convex Hulls + // Parameters for convex hull routine that ships with Bullet + public static int CSHullMaxDepthSplit { get; private set; } + public static int CSHullMaxDepthSplitForSimpleShapes { get; private set; } + public static float CSHullConcavityThresholdPercent { get; private set; } + public static float CSHullVolumeConservationThresholdPercent { get; private set; } + public static int CSHullMaxVertices { get; private set; } + public static float CSHullMaxSkinWidth { get; private set; } + public static float BHullMaxVerticesPerHull { get; private set; } // 100 + public static float BHullMinClusters { get; private set; } // 2 + public static float BHullCompacityWeight { get; private set; } // 0.1 + public static float BHullVolumeWeight { get; private set; } // 0.0 + public static float BHullConcavity { get; private set; } // 100 + public static bool BHullAddExtraDistPoints { get; private set; } // false + public static bool BHullAddNeighboursDistPoints { get; private set; } // false + public static bool BHullAddFacesPoints { get; private set; } // false + public static bool BHullShouldAdjustCollisionMargin { get; private set; } // false + public static float WhichHACD { get; private set; } // zero if Bullet HACD, non-zero says VHACD + // Parameters for VHACD 2.0: http://code.google.com/p/v-hacd + // To enable, set both ShouldUseBulletHACD=true and WhichHACD=1 + // http://kmamou.blogspot.ca/2014/12/v-hacd-20-parameters-description.html + public static float VHACDresolution { get; private set; } // 100,000 max number of voxels generated during voxelization stage + public static float VHACDdepth { get; private set; } // 20 max number of clipping stages + public static float VHACDconcavity { get; private set; } // 0.0025 maximum concavity + public static float VHACDplaneDownsampling { get; private set; } // 4 granularity of search for best clipping plane + public static float VHACDconvexHullDownsampling { get; private set; } // 4 precision of hull gen process + public static float VHACDalpha { get; private set; } // 0.05 bias toward clipping along symmetry planes + public static float VHACDbeta { get; private set; } // 0.05 bias toward clipping along revolution axis + public static float VHACDgamma { get; private set; } // 0.00125 max concavity when merging + public static float VHACDpca { get; private set; } // 0 on/off normalizing mesh before decomp + public static float VHACDmode { get; private set; } // 0 0:voxel based, 1: tetrahedron based + public static float VHACDmaxNumVerticesPerCH { get; private set; } // 64 max triangles per convex hull + public static float VHACDminVolumePerCH { get; private set; } // 0.0001 sampling of generated convex hulls + + // Linkset implementation parameters + public static float LinksetImplementation { get; private set; } + public static bool LinksetOffsetCenterOfMass { get; private set; } + public static bool LinkConstraintUseFrameOffset { get; private set; } + public static bool LinkConstraintEnableTransMotor { get; private set; } + public static float LinkConstraintTransMotorMaxVel { get; private set; } + public static float LinkConstraintTransMotorMaxForce { get; private set; } + public static float LinkConstraintERP { get; private set; } + public static float LinkConstraintCFM { get; private set; } + public static float LinkConstraintSolverIterations { get; private set; } + + public static bool UseBulletRaycast { get; private set; } + + public static float PID_D { get; private set; } // derivative + public static float PID_P { get; private set; } // proportional + + public static float DebugNumber { get; private set; } // A console setable number used for debugging + + // Various constants that come from that other virtual world that shall not be named. + public const float MinGravityZ = -1f; + public const float MaxGravityZ = 28f; + public const float MinFriction = 0f; + public const float MaxFriction = 255f; + public const float MinDensity = 0.01f; + public const float MaxDensity = 22587f; + public const float MinRestitution = 0f; + public const float MaxRestitution = 1f; + + // ===================================================================================== + // ===================================================================================== + + // Base parameter definition that gets and sets parameter values via a string + public abstract class ParameterDefnBase { - defaultValue = pDefault; - setter = pSetter; - getter = pGetter; - objectSet = null; - } - public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue pGetter, PSetValue pSetter, PSetOnObject pObjSetter) - : base(pName, pDesc) - { - defaultValue = pDefault; - setter = pSetter; - getter = pGetter; - objectSet = pObjSetter; - } - // Simple parameter variable where property name is the same as the INI file name - // and the value is only a simple get and set. - public ParameterDefn(string pName, string pDesc, T pDefault) - : base(pName, pDesc) - { - defaultValue = pDefault; - setter = (s, v) => { SetValueByName(s, name, v); }; - getter = (s) => { return GetValueByName(s, name); }; - objectSet = null; - } - // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same. - private void SetValueByName(BSScene s, string pName, T val) - { - PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); - if (prop == null) + public string name; // string name of the parameter + public string desc; // a short description of what the parameter means + public ParameterDefnBase(string pName, string pDesc) { - // This should only be output when someone adds a new INI parameter and misspells the name. - s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName); - } - else - { - prop.SetValue(null, val, null); + name = pName; + desc = pDesc; } + // Set the parameter value to the default + public abstract void AssignDefault(BSScene s); + // Get the value as a string + public abstract string GetValue(BSScene s); + // Set the value to this string value + public abstract void SetValue(BSScene s, string valAsString); + // set the value on a particular object (usually sets in physics engine) + public abstract void SetOnObject(BSScene s, BSPhysObject obj); + public abstract bool HasSetOnObject { get; } } - // Use reflection to find the property named 'pName' in BSParam and return the value in same. - private T GetValueByName(BSScene s, string pName) + + // Specific parameter definition for a parameter of a specific type. + public delegate T PGetValue(BSScene s); + public delegate void PSetValue(BSScene s, T val); + public delegate void PSetOnObject(BSScene scene, BSPhysObject obj); + public sealed class ParameterDefn : ParameterDefnBase { - PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); - if (prop == null) + private T defaultValue; + private PSetValue setter; + private PGetValue getter; + private PSetOnObject objectSet; + public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue pGetter, PSetValue pSetter) + : base(pName, pDesc) { - // This should only be output when someone adds a new INI parameter and misspells the name. - s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName); + defaultValue = pDefault; + setter = pSetter; + getter = pGetter; + objectSet = null; } - return (T)prop.GetValue(null, null); - } - public override void AssignDefault(BSScene s) - { - setter(s, defaultValue); - } - public override string GetValue(BSScene s) - { - return getter(s).ToString(); - } - public override void SetValue(BSScene s, string valAsString) - { - // Get the generic type of the setter - Type genericType = setter.GetType().GetGenericArguments()[0]; - // Find the 'Parse' method on that type - System.Reflection.MethodInfo parser = null; - try + public ParameterDefn(string pName, string pDesc, T pDefault, PGetValue pGetter, PSetValue pSetter, PSetOnObject pObjSetter) + : base(pName, pDesc) { - parser = genericType.GetMethod("Parse", new Type[] { typeof(String) } ); + defaultValue = pDefault; + setter = pSetter; + getter = pGetter; + objectSet = pObjSetter; } - catch (Exception e) + // Simple parameter variable where property name is the same as the INI file name + // and the value is only a simple get and set. + public ParameterDefn(string pName, string pDesc, T pDefault) + : base(pName, pDesc) { - s.Logger.ErrorFormat("{0} Exception getting parser for type '{1}': {2}", LogHeader, genericType, e); - parser = null; + defaultValue = pDefault; + setter = (s, v) => { SetValueByName(s, name, v); }; + getter = (s) => { return GetValueByName(s, name); }; + objectSet = null; } - if (parser != null) + // Use reflection to find the property named 'pName' in BSParam and assign 'val' to same. + private void SetValueByName(BSScene s, string pName, T val) { - // Parse the input string + PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); + if (prop == null) + { + // This should only be output when someone adds a new INI parameter and misspells the name. + s.Logger.ErrorFormat("{0} SetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameters name.", LogHeader, pName); + } + else + { + prop.SetValue(null, val, null); + } + } + // Use reflection to find the property named 'pName' in BSParam and return the value in same. + private T GetValueByName(BSScene s, string pName) + { + PropertyInfo prop = typeof(BSParam).GetProperty(pName, BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); + if (prop == null) + { + // This should only be output when someone adds a new INI parameter and misspells the name. + s.Logger.ErrorFormat("{0} GetValueByName: did not find '{1}'. Verify specified property name is the same as the given INI parameter name.", LogHeader, pName); + } + return (T)prop.GetValue(null, null); + } + public override void AssignDefault(BSScene s) + { + setter(s, defaultValue); + } + public override string GetValue(BSScene s) + { + return getter(s).ToString(); + } + public override void SetValue(BSScene s, string valAsString) + { + // Get the generic type of the setter + Type genericType = setter.GetType().GetGenericArguments()[0]; + // Find the 'Parse' method on that type + System.Reflection.MethodInfo parser = null; try { - T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString }); - // Store the parsed value - setter(s, setValue); - // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue); + parser = genericType.GetMethod("Parse", new Type[] { typeof(String) } ); } - catch + catch (Exception e) { - s.Logger.ErrorFormat("{0} Failed parsing parameter value '{1}' as type '{2}'", LogHeader, valAsString, genericType); + s.Logger.ErrorFormat("{0} Exception getting parser for type '{1}': {2}", LogHeader, genericType, e); + parser = null; + } + if (parser != null) + { + // Parse the input string + try + { + T setValue = (T)parser.Invoke(genericType, new Object[] { valAsString }); + // Store the parsed value + setter(s, setValue); + // s.Logger.DebugFormat("{0} Parameter {1} = {2}", LogHeader, name, setValue); + } + catch + { + s.Logger.ErrorFormat("{0} Failed parsing parameter value '{1}' as type '{2}'", LogHeader, valAsString, genericType); + } + } + else + { + s.Logger.ErrorFormat("{0} Could not find parameter parser for type '{1}'", LogHeader, genericType); } } - else + public override bool HasSetOnObject { - s.Logger.ErrorFormat("{0} Could not find parameter parser for type '{1}'", LogHeader, genericType); + get { return objectSet != null; } + } + public override void SetOnObject(BSScene s, BSPhysObject obj) + { + if (objectSet != null) + objectSet(s, obj); } } - public override bool HasSetOnObject + + // List of all of the externally visible parameters. + // For each parameter, this table maps a text name to getter and setters. + // To add a new externally referencable/settable parameter, add the paramter storage + // location somewhere in the program and make an entry in this table with the + // getters and setters. + // It is easiest to find an existing definition and copy it. + // + // A ParameterDefn() takes the following parameters: + // -- the text name of the parameter. This is used for console input and ini file. + // -- a short text description of the parameter. This shows up in the console listing. + // -- a default value + // -- a delegate for getting the value + // -- a delegate for setting the value + // -- an optional delegate to update the value in the world. Most often used to + // push the new value to an in-world object. + // + // The single letter parameters for the delegates are: + // s = BSScene + // o = BSPhysObject + // v = value (appropriate type) + private static ParameterDefnBase[] ParameterDefinitions = { - get { return objectSet != null; } + new ParameterDefn("Active", "If 'true', false then physics is not active", + false ), + new ParameterDefn("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat", + false ), + new ParameterDefn("PhysicsTimeStep", "If separate thread, seconds to simulate each interval", + 0.089f ), + + new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", + true, + (s) => { return ShouldMeshSculptedPrim; }, + (s,v) => { ShouldMeshSculptedPrim = v; } ), + new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", + false, + (s) => { return ShouldForceSimplePrimMeshing; }, + (s,v) => { ShouldForceSimplePrimMeshing = v; } ), + new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", + true, + (s) => { return ShouldUseHullsForPhysicalObjects; }, + (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), + new ParameterDefn("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", + true ), + new ParameterDefn("ShouldUseBulletHACD", "If true, use the Bullet version of HACD", + false ), + new ParameterDefn("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims", + true ), + new ParameterDefn("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", + false ), + new ParameterDefn("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info", + true ), + + new ParameterDefn("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", + 5 ), + new ParameterDefn("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator", + 0.1f ), + + new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", + 32f, + (s) => { return MeshLOD; }, + (s,v) => { MeshLOD = v; } ), + new ParameterDefn("MeshLevelOfDetailCircular", "Level of detail for prims with circular cuts or shapes", + 32f, + (s) => { return MeshCircularLOD; }, + (s,v) => { MeshCircularLOD = v; } ), + new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", + 10f, + (s) => { return MeshMegaPrimThreshold; }, + (s,v) => { MeshMegaPrimThreshold = v; } ), + new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", + 32f, + (s) => { return MeshMegaPrimLOD; }, + (s,v) => { MeshMegaPrimLOD = v; } ), + new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", + 32f, + (s) => { return SculptLOD; }, + (s,v) => { SculptLOD = v; } ), + + new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", + 10, + (s) => { return s.m_maxSubSteps; }, + (s,v) => { s.m_maxSubSteps = (int)v; } ), + new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", + 1f / 60f, + (s) => { return s.m_fixedTimeStep; }, + (s,v) => { s.m_fixedTimeStep = v; } ), + new ParameterDefn("NominalFrameRate", "The base frame rate we claim", + 55f, + (s) => { return s.NominalFrameRate; }, + (s,v) => { s.NominalFrameRate = (int)v; } ), + new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", + 2048, + (s) => { return s.m_maxCollisionsPerFrame; }, + (s,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), + new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame", + 8000, + (s) => { return s.m_maxUpdatesPerFrame; }, + (s,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), + + new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)", + 0.0001f, + (s) => { return MinimumObjectMass; }, + (s,v) => { MinimumObjectMass = v; } ), + new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", + 10000.01f, + (s) => { return MaximumObjectMass; }, + (s,v) => { MaximumObjectMass = v; } ), + new ParameterDefn("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object", + 1000.0f, + (s) => { return MaxLinearVelocity; }, + (s,v) => { MaxLinearVelocity = v; MaxLinearVelocitySquared = v * v; } ), + new ParameterDefn("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object", + 1000.0f, + (s) => { return MaxAngularVelocity; }, + (s,v) => { MaxAngularVelocity = v; MaxAngularVelocitySquared = v * v; } ), + // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject + new ParameterDefn("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)", + 20000.0f, + (s) => { return MaxAddForceMagnitude; }, + (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), + // Density is passed around as 100kg/m3. This scales that to 1kg/m3. + // Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well + new ParameterDefn("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", + 0.01f ), + + new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", + 2200f ), + new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", + 900f ), + + new ParameterDefn("DefaultFriction", "Friction factor used on new objects", + 0.2f, + (s) => { return DefaultFriction; }, + (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ), + // For historical reasons, the viewer and simulator multiply the density by 100 + new ParameterDefn("DefaultDensity", "Density for new objects" , + 1000.0006836f, // Aluminum g/cm3 * 100 + (s) => { return DefaultDensity; }, + (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ), + new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , + 0f, + (s) => { return DefaultRestitution; }, + (s,v) => { DefaultRestitution = v; s.UnmanagedParams[0].defaultRestitution = v; } ), + new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", + 0.04f, + (s) => { return CollisionMargin; }, + (s,v) => { CollisionMargin = v; s.UnmanagedParams[0].collisionMargin = v; } ), + new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)", + -9.80665f, + (s) => { return Gravity; }, + (s,v) => { Gravity = v; s.UnmanagedParams[0].gravity = v; }, + (s,o) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,Gravity)); } ), + + + new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", + 0f, + (s) => { return LinearDamping; }, + (s,v) => { LinearDamping = v; }, + (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ), + new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", + 0f, + (s) => { return AngularDamping; }, + (s,v) => { AngularDamping = v; }, + (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ), + new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", + 0.2f, + (s) => { return DeactivationTime; }, + (s,v) => { DeactivationTime = v; }, + (s,o) => { s.PE.SetDeactivationTime(o.PhysBody, DeactivationTime); } ), + new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", + 0.8f, + (s) => { return LinearSleepingThreshold; }, + (s,v) => { LinearSleepingThreshold = v;}, + (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ), + new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", + 1.0f, + (s) => { return AngularSleepingThreshold; }, + (s,v) => { AngularSleepingThreshold = v;}, + (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ), + new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , + 0.0f, // set to zero to disable + (s) => { return CcdMotionThreshold; }, + (s,v) => { CcdMotionThreshold = v;}, + (s,o) => { s.PE.SetCcdMotionThreshold(o.PhysBody, CcdMotionThreshold); } ), + new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , + 0.2f, + (s) => { return CcdSweptSphereRadius; }, + (s,v) => { CcdSweptSphereRadius = v;}, + (s,o) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, CcdSweptSphereRadius); } ), + new ParameterDefn("ContactProcessingThreshold", "Distance above which contacts can be discarded (0 means no discard)" , + 0.0f, + (s) => { return ContactProcessingThreshold; }, + (s,v) => { ContactProcessingThreshold = v;}, + (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), + + new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", + (float)BSTerrainPhys.TerrainImplementation.Heightmap ), + new ParameterDefn("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , + 2 ), + new ParameterDefn("TerrainGroundPlane", "Altitude of ground plane used to keep things from falling to infinity" , + -500.0f ), + new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , + 0.3f ), + new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , + 0.8f ), + new ParameterDefn("TerrainRestitution", "Bouncyness" , + 0f ), + new ParameterDefn("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" , + 0.0f ), + new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , + 0.04f ), + + new ParameterDefn("AvatarToAvatarCollisionsByDefault", "Should avatars collide with other avatars by default?", + true), + new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", + 0.2f ), + new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", + 0.95f ), + new ParameterDefn("AvatarWalkVelocityFactor", "Speed multiplier if avatar is walking", + 1.0f ), + new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", + 1.3f ), + // For historical reasons, density is reported * 100 + new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation. Scaled times 100.", + 350f) , // 3.5 * 100 + new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", + 0f ), + new ParameterDefn("AvatarShape", "Code for avatar physical shape: 0:capsule, 1:cube, 2:ovoid, 2:mesh", + BSShapeCollection.AvatarShapeCube ) , + new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", + 0.6f ) , + new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", + 0.45f ), + new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", + 1.5f ), + new ParameterDefn("AvatarUseBefore09SizeComputation", "Use the old fudge method of computing avatar capsule size", + true ), + new ParameterDefn("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground", + 0f ), + new ParameterDefn("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground", + 0f ), + new ParameterDefn("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground", + 0f ), + new ParameterDefn("AvatarFlyingGroundMargin", "Meters avatar is kept above the ground when flying", + 5f ), + new ParameterDefn("AvatarFlyingGroundUpForce", "Upward force applied to the avatar to keep it at flying ground margin", + 2.0f ), + new ParameterDefn("AvatarAddForceFrames", "Frames to allow AddForce to apply before checking for stationary", + 10 ), + new ParameterDefn("AvatarTerminalVelocity", "Terminal Velocity of falling avatar", + -54.0f ), + new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", + 0.1f ), + new ParameterDefn("AvatarAddForcePushFactor", "BSCharacter.AddForce is multiplied by this and mass to be like other physics engines", + 0.315f ), + new ParameterDefn("AvatarStopZeroThreshold", "Movement velocity below which avatar is assumed to be stopped", + 0.45f, + (s) => { return (float)AvatarStopZeroThreshold; }, + (s,v) => { AvatarStopZeroThreshold = v; AvatarStopZeroThresholdSquared = v * v; } ), + new ParameterDefn("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", + 1.0f ), + new ParameterDefn("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.", + 4 ), + new ParameterDefn("AvatarStepHeight", "Height of a step obstacle to consider step correction", + 0.999f ) , + new ParameterDefn("AvatarStepAngle", "The angle (in radians) for a vertical surface to be considered a step", + 0.3f ) , + new ParameterDefn("AvatarStepGroundFudge", "Fudge factor subtracted from avatar base when comparing collision height", + 0.1f ) , + new ParameterDefn("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", + 2f ), + new ParameterDefn("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", + 0f ), + new ParameterDefn("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step", + 0.8f ), + new ParameterDefn("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs", + 1 ), + + new ParameterDefn("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", + 1000.0f, + (s) => { return (float)VehicleMaxLinearVelocity; }, + (s,v) => { VehicleMaxLinearVelocity = v; VehicleMaxLinearVelocitySquared = v * v; } ), + new ParameterDefn("VehicleMinLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", + 0.001f, + (s) => { return (float)VehicleMinLinearVelocity; }, + (s,v) => { VehicleMinLinearVelocity = v; VehicleMinLinearVelocitySquared = v * v; } ), + new ParameterDefn("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle", + 12.0f, + (s) => { return (float)VehicleMaxAngularVelocity; }, + (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), + new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", + 0.0f ), + new ParameterDefn("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)", + new Vector3(1f, 1f, 1f) ), + new ParameterDefn("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)", + new Vector3(1f, 1f, 1f) ), + new ParameterDefn("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)", + new Vector3(1f, 1f, 1f) ), + new ParameterDefn("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", + 0.0f ), + new ParameterDefn("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", + 0.0f ), + new ParameterDefn("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", + 0.2f ), + new ParameterDefn("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", + 60.0f ), + new ParameterDefn("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect", + true ), + new ParameterDefn("VehicleLinearDeflectionNotCollidingNoZ", "Turn on/off linear deflection Z effect on non-colliding vehicles", + true ), + new ParameterDefn("VehicleEnableAngularVerticalAttraction", "Turn on/off vehicle angular vertical attraction effect", + true ), + new ParameterDefn("VehicleAngularVerticalAttractionAlgorithm", "Select vertical attraction algo. You need to look at the source.", + 0 ), + new ParameterDefn("VehicleEnableAngularDeflection", "Turn on/off vehicle angular deflection effect", + true ), + new ParameterDefn("VehicleEnableAngularBanking", "Turn on/off vehicle angular banking effect", + true ), + + new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", + 0f, + (s) => { return MaxPersistantManifoldPoolSize; }, + (s,v) => { MaxPersistantManifoldPoolSize = v; s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ), + new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", + 0f, + (s) => { return MaxCollisionAlgorithmPoolSize; }, + (s,v) => { MaxCollisionAlgorithmPoolSize = v; s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ), + new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", + false, + (s) => { return ShouldDisableContactPoolDynamicAllocation; }, + (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; + s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), + new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", + false, + (s) => { return ShouldForceUpdateAllAabbs; }, + (s,v) => { ShouldForceUpdateAllAabbs = v; s.UnmanagedParams[0].shouldForceUpdateAllAabbs = NumericBool(v); } ), + new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", + true, + (s) => { return ShouldRandomizeSolverOrder; }, + (s,v) => { ShouldRandomizeSolverOrder = v; s.UnmanagedParams[0].shouldRandomizeSolverOrder = NumericBool(v); } ), + new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", + true, + (s) => { return ShouldSplitSimulationIslands; }, + (s,v) => { ShouldSplitSimulationIslands = v; s.UnmanagedParams[0].shouldSplitSimulationIslands = NumericBool(v); } ), + new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", + true, + (s) => { return ShouldEnableFrictionCaching; }, + (s,v) => { ShouldEnableFrictionCaching = v; s.UnmanagedParams[0].shouldEnableFrictionCaching = NumericBool(v); } ), + new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)", + 0f, // zero says use Bullet default + (s) => { return NumberOfSolverIterations; }, + (s,v) => { NumberOfSolverIterations = v; s.UnmanagedParams[0].numberOfSolverIterations = v; } ), + new ParameterDefn("UseSingleSidedMeshes", "Whether to compute collisions based on single sided meshes.", + true, + (s) => { return UseSingleSidedMeshes; }, + (s,v) => { UseSingleSidedMeshes = v; s.UnmanagedParams[0].useSingleSidedMeshes = NumericBool(v); } ), + new ParameterDefn("GlobalContactBreakingThreshold", "Amount of shape radius before breaking a collision contact (0 says Bullet default (0.2))", + 0f, + (s) => { return GlobalContactBreakingThreshold; }, + (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), + new ParameterDefn("PhysicsUnmanLoggingFrames", "If non-zero, frames between output of detailed unmanaged physics statistics", + 0f, + (s) => { return PhysicsUnmanLoggingFrames; }, + (s,v) => { PhysicsUnmanLoggingFrames = v; s.UnmanagedParams[0].physicsLoggingFrames = v; } ), + + new ParameterDefn("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", + 7 ), + new ParameterDefn("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", + 2 ), + new ParameterDefn("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", + 5f ), + new ParameterDefn("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", + 5f ), + new ParameterDefn("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.", + 32 ), + new ParameterDefn("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", + 0f ), + + new ParameterDefn("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull", + 200f ), + new ParameterDefn("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh", + 10f ), + new ParameterDefn("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls", + 20f ), + new ParameterDefn("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull", + 0.1f ), + new ParameterDefn("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be", + 10f ), + new ParameterDefn("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors", + true ), + new ParameterDefn("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls", + true ), + new ParameterDefn("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces", + true ), + new ParameterDefn("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin", + false ), + + new ParameterDefn("WhichHACD", "zero if Bullet HACD, non-zero says VHACD", + 0f ), + new ParameterDefn("VHACDresolution", "max number of voxels generated during voxelization stage", + 100000f ), + new ParameterDefn("VHACDdepth", "max number of clipping stages", + 20f ), + new ParameterDefn("VHACDconcavity", "maximum concavity", + 0.0025f ), + new ParameterDefn("VHACDplaneDownsampling", "granularity of search for best clipping plane", + 4f ), + new ParameterDefn("VHACDconvexHullDownsampling", "precision of hull gen process", + 4f ), + new ParameterDefn("VHACDalpha", "bias toward clipping along symmetry planes", + 0.05f ), + new ParameterDefn("VHACDbeta", "bias toward clipping along revolution axis", + 0.05f ), + new ParameterDefn("VHACDgamma", "max concavity when merging", + 0.00125f ), + new ParameterDefn("VHACDpca", "on/off normalizing mesh before decomp", + 0f ), + new ParameterDefn("VHACDmode", "0:voxel based, 1: tetrahedron based", + 0f ), + new ParameterDefn("VHACDmaxNumVerticesPerCH", "max triangles per convex hull", + 64f ), + new ParameterDefn("VHACDminVolumePerCH", "sampling of generated convex hulls", + 0.0001f ), + + new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", + (float)BSLinkset.LinksetImplementation.Compound ), + new ParameterDefn("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same", + true ), + new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", + false ), + new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", + true ), + new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", + 5.0f ), + new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", + 0.1f ), + new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", + 0.1f ), + new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", + 0.1f ), + new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", + 40 ), + + new ParameterDefn("UseBulletRaycast", "If 'true', use the raycast function of the Bullet physics engine", + true ), + + new ParameterDefn("DebugNumber", "A console setable number sometimes used for debugging", + 1.0f ), + + new ParameterDefn("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", + 0, + (s) => { return s.PhysicsMetricDumpFrames; }, + (s,v) => { s.PhysicsMetricDumpFrames = v; } ), + new ParameterDefn("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool", + 0f, + (s) => { return 0f; }, + (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ), + new ParameterDefn("ResetConstraintSolver", "Setting this is any value resets the constraint solver", + 0f, + (s) => { return 0f; }, + (s,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ), + }; + + // Convert a boolean to our numeric true and false values + public static float NumericBool(bool b) + { + return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); } - public override void SetOnObject(BSScene s, BSPhysObject obj) + + // Convert numeric true and false values to a boolean + public static bool BoolNumeric(float b) { - if (objectSet != null) - objectSet(s, obj); + return (b == ConfigurationParameters.numericTrue ? true : false); } - } - // List of all of the externally visible parameters. - // For each parameter, this table maps a text name to getter and setters. - // To add a new externally referencable/settable parameter, add the paramter storage - // location somewhere in the program and make an entry in this table with the - // getters and setters. - // It is easiest to find an existing definition and copy it. - // - // A ParameterDefn() takes the following parameters: - // -- the text name of the parameter. This is used for console input and ini file. - // -- a short text description of the parameter. This shows up in the console listing. - // -- a default value - // -- a delegate for getting the value - // -- a delegate for setting the value - // -- an optional delegate to update the value in the world. Most often used to - // push the new value to an in-world object. - // - // The single letter parameters for the delegates are: - // s = BSScene - // o = BSPhysObject - // v = value (appropriate type) - private static ParameterDefnBase[] ParameterDefinitions = - { - new ParameterDefn("Active", "If 'true', false then physics is not active", - false ), - new ParameterDefn("UseSeparatePhysicsThread", "If 'true', the physics engine runs independent from the simulator heartbeat", - false ), - new ParameterDefn("PhysicsTimeStep", "If separate thread, seconds to simulate each interval", - 0.089f ), - - new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", - true, - (s) => { return ShouldMeshSculptedPrim; }, - (s,v) => { ShouldMeshSculptedPrim = v; } ), - new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects", - false, - (s) => { return ShouldForceSimplePrimMeshing; }, - (s,v) => { ShouldForceSimplePrimMeshing = v; } ), - new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects", - true, - (s) => { return ShouldUseHullsForPhysicalObjects; }, - (s,v) => { ShouldUseHullsForPhysicalObjects = v; } ), - new ParameterDefn("ShouldRemoveZeroWidthTriangles", "If true, remove degenerate triangles from meshes", - true ), - new ParameterDefn("ShouldUseBulletHACD", "If true, use the Bullet version of HACD", - false ), - new ParameterDefn("ShouldUseSingleConvexHullForPrims", "If true, use a single convex hull shape for physical prims", - true ), - new ParameterDefn("ShouldUseGImpactShapeForPrims", "If true, use a GImpact shape for prims with cuts and twists", - false ), - new ParameterDefn("ShouldUseAssetHulls", "If true, use hull if specified in the mesh asset info", - true ), - - new ParameterDefn("CrossingFailuresBeforeOutOfBounds", "How forgiving we are about getting into adjactent regions", - 5 ), - new ParameterDefn("UpdateVelocityChangeThreshold", "Change in updated velocity required before reporting change to simulator", - 0.1f ), - - new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", - 32f, - (s) => { return MeshLOD; }, - (s,v) => { MeshLOD = v; } ), - new ParameterDefn("MeshLevelOfDetailCircular", "Level of detail for prims with circular cuts or shapes", - 32f, - (s) => { return MeshCircularLOD; }, - (s,v) => { MeshCircularLOD = v; } ), - new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD", - 10f, - (s) => { return MeshMegaPrimThreshold; }, - (s,v) => { MeshMegaPrimThreshold = v; } ), - new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters", - 32f, - (s) => { return MeshMegaPrimLOD; }, - (s,v) => { MeshMegaPrimLOD = v; } ), - new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)", - 32f, - (s) => { return SculptLOD; }, - (s,v) => { SculptLOD = v; } ), - - new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps", - 10, - (s) => { return s.m_maxSubSteps; }, - (s,v) => { s.m_maxSubSteps = (int)v; } ), - new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)", - 1f / 60f, - (s) => { return s.m_fixedTimeStep; }, - (s,v) => { s.m_fixedTimeStep = v; } ), - new ParameterDefn("NominalFrameRate", "The base frame rate we claim", - 55f, - (s) => { return s.NominalFrameRate; }, - (s,v) => { s.NominalFrameRate = (int)v; } ), - new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame", - 2048, - (s) => { return s.m_maxCollisionsPerFrame; }, - (s,v) => { s.m_maxCollisionsPerFrame = (int)v; } ), - new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame", - 8000, - (s) => { return s.m_maxUpdatesPerFrame; }, - (s,v) => { s.m_maxUpdatesPerFrame = (int)v; } ), - - new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)", - 0.0001f, - (s) => { return MinimumObjectMass; }, - (s,v) => { MinimumObjectMass = v; } ), - new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)", - 10000.01f, - (s) => { return MaximumObjectMass; }, - (s,v) => { MaximumObjectMass = v; } ), - new ParameterDefn("MaxLinearVelocity", "Maximum velocity magnitude that can be assigned to an object", - 1000.0f, - (s) => { return MaxLinearVelocity; }, - (s,v) => { MaxLinearVelocity = v; MaxLinearVelocitySquared = v * v; } ), - new ParameterDefn("MaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to an object", - 1000.0f, - (s) => { return MaxAngularVelocity; }, - (s,v) => { MaxAngularVelocity = v; MaxAngularVelocitySquared = v * v; } ), - // LL documentation says thie number should be 20f for llApplyImpulse and 200f for llRezObject - new ParameterDefn("MaxAddForceMagnitude", "Maximum force that can be applied by llApplyImpulse (SL says 20f)", - 20000.0f, - (s) => { return MaxAddForceMagnitude; }, - (s,v) => { MaxAddForceMagnitude = v; MaxAddForceMagnitudeSquared = v * v; } ), - // Density is passed around as 100kg/m3. This scales that to 1kg/m3. - // Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well - new ParameterDefn("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", - 0.01f ), - - new ParameterDefn("PID_D", "Derivitive factor for motion smoothing", - 2200f ), - new ParameterDefn("PID_P", "Parameteric factor for motion smoothing", - 900f ), - - new ParameterDefn("DefaultFriction", "Friction factor used on new objects", - 0.2f, - (s) => { return DefaultFriction; }, - (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ), - // For historical reasons, the viewer and simulator multiply the density by 100 - new ParameterDefn("DefaultDensity", "Density for new objects" , - 1000.0006836f, // Aluminum g/cm3 * 100 - (s) => { return DefaultDensity; }, - (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ), - new ParameterDefn("DefaultRestitution", "Bouncyness of an object" , - 0f, - (s) => { return DefaultRestitution; }, - (s,v) => { DefaultRestitution = v; s.UnmanagedParams[0].defaultRestitution = v; } ), - new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", - 0.04f, - (s) => { return CollisionMargin; }, - (s,v) => { CollisionMargin = v; s.UnmanagedParams[0].collisionMargin = v; } ), - new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)", - -9.80665f, - (s) => { return Gravity; }, - (s,v) => { Gravity = v; s.UnmanagedParams[0].gravity = v; }, - (s,o) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,Gravity)); } ), - - - new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)", - 0f, - (s) => { return LinearDamping; }, - (s,v) => { LinearDamping = v; }, - (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ), - new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)", - 0f, - (s) => { return AngularDamping; }, - (s,v) => { AngularDamping = v; }, - (s,o) => { s.PE.SetDamping(o.PhysBody, LinearDamping, AngularDamping); } ), - new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static", - 0.2f, - (s) => { return DeactivationTime; }, - (s,v) => { DeactivationTime = v; }, - (s,o) => { s.PE.SetDeactivationTime(o.PhysBody, DeactivationTime); } ), - new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static", - 0.8f, - (s) => { return LinearSleepingThreshold; }, - (s,v) => { LinearSleepingThreshold = v;}, - (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ), - new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static", - 1.0f, - (s) => { return AngularSleepingThreshold; }, - (s,v) => { AngularSleepingThreshold = v;}, - (s,o) => { s.PE.SetSleepingThresholds(o.PhysBody, LinearSleepingThreshold, AngularSleepingThreshold); } ), - new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" , - 0.0f, // set to zero to disable - (s) => { return CcdMotionThreshold; }, - (s,v) => { CcdMotionThreshold = v;}, - (s,o) => { s.PE.SetCcdMotionThreshold(o.PhysBody, CcdMotionThreshold); } ), - new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" , - 0.2f, - (s) => { return CcdSweptSphereRadius; }, - (s,v) => { CcdSweptSphereRadius = v;}, - (s,o) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, CcdSweptSphereRadius); } ), - new ParameterDefn("ContactProcessingThreshold", "Distance above which contacts can be discarded (0 means no discard)" , - 0.0f, - (s) => { return ContactProcessingThreshold; }, - (s,v) => { ContactProcessingThreshold = v;}, - (s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ), - - new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)", - (float)BSTerrainPhys.TerrainImplementation.Heightmap ), - new ParameterDefn("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" , - 2 ), - new ParameterDefn("TerrainGroundPlane", "Altitude of ground plane used to keep things from falling to infinity" , - -500.0f ), - new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , - 0.3f ), - new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" , - 0.8f ), - new ParameterDefn("TerrainRestitution", "Bouncyness" , - 0f ), - new ParameterDefn("TerrainContactProcessingThreshold", "Distance from terrain to stop processing collisions" , - 0.0f ), - new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , - 0.04f ), - - new ParameterDefn("AvatarToAvatarCollisionsByDefault", "Should avatars collide with other avatars by default?", - true), - new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", - 0.2f ), - new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", - 0.95f ), - new ParameterDefn("AvatarWalkVelocityFactor", "Speed multiplier if avatar is walking", - 1.0f ), - new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", - 1.3f ), - // For historical reasons, density is reported * 100 - new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation. Scaled times 100.", - 350f) , // 3.5 * 100 - new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", - 0f ), - new ParameterDefn("AvatarShape", "Code for avatar physical shape: 0:capsule, 1:cube, 2:ovoid, 2:mesh", - BSShapeCollection.AvatarShapeCube ) , - new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", - 0.6f ) , - new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule", - 0.45f ), - new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar", - 1.5f ), - new ParameterDefn("AvatarUseBefore09SizeComputation", "Use the old fudge method of computing avatar capsule size", - true ), - new ParameterDefn("AvatarHeightLowFudge", "A fudge factor to make small avatars stand on the ground", - 0f ), - new ParameterDefn("AvatarHeightMidFudge", "A fudge distance to adjust average sized avatars to be standing on ground", - 0f ), - new ParameterDefn("AvatarHeightHighFudge", "A fudge factor to make tall avatars stand on the ground", - 0f ), - new ParameterDefn("AvatarFlyingGroundMargin", "Meters avatar is kept above the ground when flying", - 5f ), - new ParameterDefn("AvatarFlyingGroundUpForce", "Upward force applied to the avatar to keep it at flying ground margin", - 2.0f ), - new ParameterDefn("AvatarAddForceFrames", "Frames to allow AddForce to apply before checking for stationary", - 10 ), - new ParameterDefn("AvatarTerminalVelocity", "Terminal Velocity of falling avatar", - -54.0f ), - new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions", - 0.1f ), - new ParameterDefn("AvatarAddForcePushFactor", "BSCharacter.AddForce is multiplied by this and mass to be like other physics engines", - 0.315f ), - new ParameterDefn("AvatarStopZeroThreshold", "Movement velocity below which avatar is assumed to be stopped", - 0.45f, - (s) => { return (float)AvatarStopZeroThreshold; }, - (s,v) => { AvatarStopZeroThreshold = v; AvatarStopZeroThresholdSquared = v * v; } ), - new ParameterDefn("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground", - 1.0f ), - new ParameterDefn("AvatarJumpFrames", "Number of frames to allow jump forces. Changes jump height.", - 4 ), - new ParameterDefn("AvatarStepHeight", "Height of a step obstacle to consider step correction", - 0.999f ) , - new ParameterDefn("AvatarStepAngle", "The angle (in radians) for a vertical surface to be considered a step", - 0.3f ) , - new ParameterDefn("AvatarStepGroundFudge", "Fudge factor subtracted from avatar base when comparing collision height", - 0.1f ) , - new ParameterDefn("AvatarStepApproachFactor", "Factor to control angle of approach to step (0=straight on)", - 2f ), - new ParameterDefn("AvatarStepForceFactor", "Controls the amount of force up applied to step up onto a step", - 0f ), - new ParameterDefn("AvatarStepUpCorrectionFactor", "Multiplied by height of step collision to create up movement at step", - 0.8f ), - new ParameterDefn("AvatarStepSmoothingSteps", "Number of frames after a step collision that we continue walking up stairs", - 1 ), - - new ParameterDefn("VehicleMaxLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", - 1000.0f, - (s) => { return (float)VehicleMaxLinearVelocity; }, - (s,v) => { VehicleMaxLinearVelocity = v; VehicleMaxLinearVelocitySquared = v * v; } ), - new ParameterDefn("VehicleMinLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle", - 0.001f, - (s) => { return (float)VehicleMinLinearVelocity; }, - (s,v) => { VehicleMinLinearVelocity = v; VehicleMinLinearVelocitySquared = v * v; } ), - new ParameterDefn("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle", - 12.0f, - (s) => { return (float)VehicleMaxAngularVelocity; }, - (s,v) => { VehicleMaxAngularVelocity = v; VehicleMaxAngularVelocitySq = v * v; } ), - new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", - 0.0f ), - new ParameterDefn("VehicleLinearFactor", "Fraction of physical linear changes applied to vehicle (<0,0,0> to <1,1,1>)", - new Vector3(1f, 1f, 1f) ), - new ParameterDefn("VehicleAngularFactor", "Fraction of physical angular changes applied to vehicle (<0,0,0> to <1,1,1>)", - new Vector3(1f, 1f, 1f) ), - new ParameterDefn("VehicleInertiaFactor", "Fraction of physical inertia applied (<0,0,0> to <1,1,1>)", - new Vector3(1f, 1f, 1f) ), - new ParameterDefn("VehicleFriction", "Friction of vehicle on the ground (0.0 - 1.0)", - 0.0f ), - new ParameterDefn("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", - 0.0f ), - new ParameterDefn("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", - 0.2f ), - new ParameterDefn("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", - 60.0f ), - new ParameterDefn("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect", - true ), - new ParameterDefn("VehicleLinearDeflectionNotCollidingNoZ", "Turn on/off linear deflection Z effect on non-colliding vehicles", - true ), - new ParameterDefn("VehicleEnableAngularVerticalAttraction", "Turn on/off vehicle angular vertical attraction effect", - true ), - new ParameterDefn("VehicleAngularVerticalAttractionAlgorithm", "Select vertical attraction algo. You need to look at the source.", - 0 ), - new ParameterDefn("VehicleEnableAngularDeflection", "Turn on/off vehicle angular deflection effect", - true ), - new ParameterDefn("VehicleEnableAngularBanking", "Turn on/off vehicle angular banking effect", - true ), - - new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", - 0f, - (s) => { return MaxPersistantManifoldPoolSize; }, - (s,v) => { MaxPersistantManifoldPoolSize = v; s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ), - new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)", - 0f, - (s) => { return MaxCollisionAlgorithmPoolSize; }, - (s,v) => { MaxCollisionAlgorithmPoolSize = v; s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ), - new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count", - false, - (s) => { return ShouldDisableContactPoolDynamicAllocation; }, - (s,v) => { ShouldDisableContactPoolDynamicAllocation = v; - s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = NumericBool(v); } ), - new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step", - false, - (s) => { return ShouldForceUpdateAllAabbs; }, - (s,v) => { ShouldForceUpdateAllAabbs = v; s.UnmanagedParams[0].shouldForceUpdateAllAabbs = NumericBool(v); } ), - new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction", - true, - (s) => { return ShouldRandomizeSolverOrder; }, - (s,v) => { ShouldRandomizeSolverOrder = v; s.UnmanagedParams[0].shouldRandomizeSolverOrder = NumericBool(v); } ), - new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands", - true, - (s) => { return ShouldSplitSimulationIslands; }, - (s,v) => { ShouldSplitSimulationIslands = v; s.UnmanagedParams[0].shouldSplitSimulationIslands = NumericBool(v); } ), - new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching", - true, - (s) => { return ShouldEnableFrictionCaching; }, - (s,v) => { ShouldEnableFrictionCaching = v; s.UnmanagedParams[0].shouldEnableFrictionCaching = NumericBool(v); } ), - new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)", - 0f, // zero says use Bullet default - (s) => { return NumberOfSolverIterations; }, - (s,v) => { NumberOfSolverIterations = v; s.UnmanagedParams[0].numberOfSolverIterations = v; } ), - new ParameterDefn("UseSingleSidedMeshes", "Whether to compute collisions based on single sided meshes.", - true, - (s) => { return UseSingleSidedMeshes; }, - (s,v) => { UseSingleSidedMeshes = v; s.UnmanagedParams[0].useSingleSidedMeshes = NumericBool(v); } ), - new ParameterDefn("GlobalContactBreakingThreshold", "Amount of shape radius before breaking a collision contact (0 says Bullet default (0.2))", - 0f, - (s) => { return GlobalContactBreakingThreshold; }, - (s,v) => { GlobalContactBreakingThreshold = v; s.UnmanagedParams[0].globalContactBreakingThreshold = v; } ), - new ParameterDefn("PhysicsUnmanLoggingFrames", "If non-zero, frames between output of detailed unmanaged physics statistics", - 0f, - (s) => { return PhysicsUnmanLoggingFrames; }, - (s,v) => { PhysicsUnmanLoggingFrames = v; s.UnmanagedParams[0].physicsLoggingFrames = v; } ), - - new ParameterDefn("CSHullMaxDepthSplit", "CS impl: max depth to split for hull. 1-10 but > 7 is iffy", - 7 ), - new ParameterDefn("CSHullMaxDepthSplitForSimpleShapes", "CS impl: max depth setting for simple prim shapes", - 2 ), - new ParameterDefn("CSHullConcavityThresholdPercent", "CS impl: concavity threshold percent (0-20)", - 5f ), - new ParameterDefn("CSHullVolumeConservationThresholdPercent", "percent volume conservation to collapse hulls (0-30)", - 5f ), - new ParameterDefn("CSHullMaxVertices", "CS impl: maximum number of vertices in output hulls. Keep < 50.", - 32 ), - new ParameterDefn("CSHullMaxSkinWidth", "CS impl: skin width to apply to output hulls.", - 0f ), - - new ParameterDefn("BHullMaxVerticesPerHull", "Bullet impl: max number of vertices per created hull", - 200f ), - new ParameterDefn("BHullMinClusters", "Bullet impl: minimum number of hulls to create per mesh", - 10f ), - new ParameterDefn("BHullCompacityWeight", "Bullet impl: weight factor for how compact to make hulls", - 20f ), - new ParameterDefn("BHullVolumeWeight", "Bullet impl: weight factor for volume in created hull", - 0.1f ), - new ParameterDefn("BHullConcavity", "Bullet impl: weight factor for how convex a created hull can be", - 10f ), - new ParameterDefn("BHullAddExtraDistPoints", "Bullet impl: whether to add extra vertices for long distance vectors", - true ), - new ParameterDefn("BHullAddNeighboursDistPoints", "Bullet impl: whether to add extra vertices between neighbor hulls", - true ), - new ParameterDefn("BHullAddFacesPoints", "Bullet impl: whether to add extra vertices to break up hull faces", - true ), - new ParameterDefn("BHullShouldAdjustCollisionMargin", "Bullet impl: whether to shrink resulting hulls to account for collision margin", - false ), - - new ParameterDefn("WhichHACD", "zero if Bullet HACD, non-zero says VHACD", - 0f ), - new ParameterDefn("VHACDresolution", "max number of voxels generated during voxelization stage", - 100000f ), - new ParameterDefn("VHACDdepth", "max number of clipping stages", - 20f ), - new ParameterDefn("VHACDconcavity", "maximum concavity", - 0.0025f ), - new ParameterDefn("VHACDplaneDownsampling", "granularity of search for best clipping plane", - 4f ), - new ParameterDefn("VHACDconvexHullDownsampling", "precision of hull gen process", - 4f ), - new ParameterDefn("VHACDalpha", "bias toward clipping along symmetry planes", - 0.05f ), - new ParameterDefn("VHACDbeta", "bias toward clipping along revolution axis", - 0.05f ), - new ParameterDefn("VHACDgamma", "max concavity when merging", - 0.00125f ), - new ParameterDefn("VHACDpca", "on/off normalizing mesh before decomp", - 0f ), - new ParameterDefn("VHACDmode", "0:voxel based, 1: tetrahedron based", - 0f ), - new ParameterDefn("VHACDmaxNumVerticesPerCH", "max triangles per convex hull", - 64f ), - new ParameterDefn("VHACDminVolumePerCH", "sampling of generated convex hulls", - 0.0001f ), - - new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)", - (float)BSLinkset.LinksetImplementation.Compound ), - new ParameterDefn("LinksetOffsetCenterOfMass", "If 'true', compute linkset center-of-mass and offset linkset position to account for same", - true ), - new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.", - false ), - new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints", - true ), - new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints", - 5.0f ), - new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints", - 0.1f ), - new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1", - 0.1f ), - new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2", - 0.1f ), - new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)", - 40 ), - - new ParameterDefn("UseBulletRaycast", "If 'true', use the raycast function of the Bullet physics engine", - true ), - - new ParameterDefn("DebugNumber", "A console setable number sometimes used for debugging", - 1.0f ), - - new ParameterDefn("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)", - 0, - (s) => { return s.PhysicsMetricDumpFrames; }, - (s,v) => { s.PhysicsMetricDumpFrames = v; } ), - new ParameterDefn("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool", - 0f, - (s) => { return 0f; }, - (s,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ), - new ParameterDefn("ResetConstraintSolver", "Setting this is any value resets the constraint solver", - 0f, - (s) => { return 0f; }, - (s,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ), - }; - - // Convert a boolean to our numeric true and false values - public static float NumericBool(bool b) - { - return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse); - } - - // Convert numeric true and false values to a boolean - public static bool BoolNumeric(float b) - { - return (b == ConfigurationParameters.numericTrue ? true : false); - } - - // Search through the parameter definitions and return the matching - // ParameterDefn structure. - // Case does not matter as names are compared after converting to lower case. - // Returns 'false' if the parameter is not found. - internal static bool TryGetParameter(string paramName, out ParameterDefnBase defn) - { - bool ret = false; - ParameterDefnBase foundDefn = null; - string pName = paramName.ToLower(); - - foreach (ParameterDefnBase parm in ParameterDefinitions) + // Search through the parameter definitions and return the matching + // ParameterDefn structure. + // Case does not matter as names are compared after converting to lower case. + // Returns 'false' if the parameter is not found. + internal static bool TryGetParameter(string paramName, out ParameterDefnBase defn) { - if (pName == parm.name.ToLower()) + bool ret = false; + ParameterDefnBase foundDefn = null; + string pName = paramName.ToLower(); + + foreach (ParameterDefnBase parm in ParameterDefinitions) { - foundDefn = parm; - ret = true; - break; + if (pName == parm.name.ToLower()) + { + foundDefn = parm; + ret = true; + break; + } + } + defn = foundDefn; + return ret; + } + + // Pass through the settable parameters and set the default values + internal static void SetParameterDefaultValues(BSScene physicsScene) + { + foreach (ParameterDefnBase parm in ParameterDefinitions) + { + parm.AssignDefault(physicsScene); } } - defn = foundDefn; - return ret; - } - // Pass through the settable parameters and set the default values - internal static void SetParameterDefaultValues(BSScene physicsScene) - { - foreach (ParameterDefnBase parm in ParameterDefinitions) + // Get user set values out of the ini file. + internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg) { - parm.AssignDefault(physicsScene); - } - } - - // Get user set values out of the ini file. - internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg) - { - foreach (ParameterDefnBase parm in ParameterDefinitions) - { - parm.SetValue(physicsScene, cfg.GetString(parm.name, parm.GetValue(physicsScene))); - } - } - - internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; - - // This creates an array in the correct format for returning the list of - // parameters. This is used by the 'list' option of the 'physics' command. - internal static void BuildParameterTable() - { - if (SettableParameters.Length < ParameterDefinitions.Length) - { - List entries = new List(); - for (int ii = 0; ii < ParameterDefinitions.Length; ii++) + foreach (ParameterDefnBase parm in ParameterDefinitions) { - ParameterDefnBase pd = ParameterDefinitions[ii]; - entries.Add(new PhysParameterEntry(pd.name, pd.desc)); + parm.SetValue(physicsScene, cfg.GetString(parm.name, parm.GetValue(physicsScene))); } - - // make the list alphabetical for ease of finding anything - entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); }); - - SettableParameters = entries.ToArray(); } - } - // ===================================================================== - // ===================================================================== - // There are parameters that, when set, cause things to happen in the physics engine. - // This causes the broadphase collision cache to be cleared. - private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v) - { - BSScene physScene = pPhysScene; - physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetBroadphasePoolTainted", delegate() - { - physScene.PE.ResetBroadphasePool(physScene.World); - }); - } + internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1]; - // This causes the constraint solver cache to be cleared and reset. - private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v) - { - BSScene physScene = pPhysScene; - physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetConstraintSolver", delegate() + // This creates an array in the correct format for returning the list of + // parameters. This is used by the 'list' option of the 'physics' command. + internal static void BuildParameterTable() { - physScene.PE.ResetConstraintSolver(physScene.World); - }); + if (SettableParameters.Length < ParameterDefinitions.Length) + { + List entries = new List(); + for (int ii = 0; ii < ParameterDefinitions.Length; ii++) + { + ParameterDefnBase pd = ParameterDefinitions[ii]; + entries.Add(new PhysParameterEntry(pd.name, pd.desc)); + } + + // make the list alphabetical for ease of finding anything + entries.Sort((ppe1, ppe2) => { return ppe1.name.CompareTo(ppe2.name); }); + + SettableParameters = entries.ToArray(); + } + } + + // ===================================================================== + // ===================================================================== + // There are parameters that, when set, cause things to happen in the physics engine. + // This causes the broadphase collision cache to be cleared. + private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v) + { + BSScene physScene = pPhysScene; + physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetBroadphasePoolTainted", delegate() + { + physScene.PE.ResetBroadphasePool(physScene.World); + }); + } + + // This causes the constraint solver cache to be cleared and reset. + private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v) + { + BSScene physScene = pPhysScene; + physScene.TaintedObject(BSScene.DetailLogZero, "BSParam.ResetConstraintSolver", delegate() + { + physScene.PE.ResetConstraintSolver(physScene.World); + }); + } } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs index 6aa24d5331..ff0570be98 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs @@ -34,676 +34,676 @@ using OpenSim.Region.PhysicsModules.SharedBase; namespace OpenSim.Region.PhysicsModule.BulletS { -/* - * Class to wrap all objects. - * The rest of BulletSim doesn't need to keep checking for avatars or prims - * unless the difference is significant. - * - * Variables in the physicsl objects are in three forms: - * VariableName: used by the simulator and performs taint operations, etc - * RawVariableName: direct reference to the BulletSim storage for the variable value - * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. - * The last one should only be referenced in taint-time. - */ + /* + * Class to wrap all objects. + * The rest of BulletSim doesn't need to keep checking for avatars or prims + * unless the difference is significant. + * + * Variables in the physicsl objects are in three forms: + * VariableName: used by the simulator and performs taint operations, etc + * RawVariableName: direct reference to the BulletSim storage for the variable value + * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. + * The last one should only be referenced in taint-time. + */ -/* - * As of 20121221, the following are the call sequences (going down) for different script physical functions: - * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce - * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce - * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse - * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v - * BS.ApplyCentralForce BS.ApplyTorque - */ + /* + * As of 20121221, the following are the call sequences (going down) for different script physical functions: + * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce + * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce + * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse + * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v + * BS.ApplyCentralForce BS.ApplyTorque + */ -// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc. -public enum UpdatedProperties : uint -{ - Position = 1 << 0, - Orientation = 1 << 1, - Velocity = 1 << 2, - Acceleration = 1 << 3, - RotationalVelocity = 1 << 4, - EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity, -} -public abstract class BSPhysObject : PhysicsActor -{ - protected BSPhysObject() + // Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc. + public enum UpdatedProperties : uint { + Position = 1 << 0, + Orientation = 1 << 1, + Velocity = 1 << 2, + Acceleration = 1 << 3, + RotationalVelocity = 1 << 4, + EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity, } - protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) + public abstract class BSPhysObject : PhysicsActor { - IsInitialized = false; - - PhysScene = parentScene; - LocalID = localID; - PhysObjectName = name; - Name = name; // PhysicsActor also has the name of the object. Someday consolidate. - TypeName = typeName; - - // Oddity if object is destroyed and recreated very quickly it could still have the old body. - if (!PhysBody.HasPhysicalBody) - PhysBody = new BulletBody(localID); - - // Clean out anything that might be in the physical actor list. - // Again, a workaround for destroying and recreating an object very quickly. - PhysicalActors.Dispose(); - - UserSetCenterOfMassDisplacement = null; - - PrimAssetState = PrimAssetCondition.Unknown; - - // Initialize variables kept in base. - // Beware that these cause taints to be queued whch can cause race conditions on startup. - GravModifier = 1.0f; - Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); - HoverActive = false; - - // Default material type. Also sets Friction, Restitution and Density. - SetMaterial((int)MaterialAttributes.Material.Wood); - - CollisionsLastTickStep = -1; - - SubscribedEventsMs = 0; - // Crazy values that will never be true - CollidingStep = BSScene.NotASimulationStep; - CollidingGroundStep = BSScene.NotASimulationStep; - CollisionAccumulation = BSScene.NotASimulationStep; - ColliderIsMoving = false; - CollisionScore = 0; - - // All axis free. - LockedLinearAxis = LockedAxisFree; - LockedAngularAxis = LockedAxisFree; - } - - // Tell the object to clean up. - public virtual void Destroy() - { - PhysicalActors.Enable(false); - PhysScene.TaintedObject(LocalID, "BSPhysObject.Destroy", delegate() + protected BSPhysObject() { + } + protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName) + { + IsInitialized = false; + + PhysScene = parentScene; + LocalID = localID; + PhysObjectName = name; + Name = name; // PhysicsActor also has the name of the object. Someday consolidate. + TypeName = typeName; + + // Oddity if object is destroyed and recreated very quickly it could still have the old body. + if (!PhysBody.HasPhysicalBody) + PhysBody = new BulletBody(localID); + + // Clean out anything that might be in the physical actor list. + // Again, a workaround for destroying and recreating an object very quickly. PhysicalActors.Dispose(); - }); - } - public BSScene PhysScene { get; protected set; } - // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor - public string PhysObjectName { get; protected set; } - public string TypeName { get; protected set; } + UserSetCenterOfMassDisplacement = null; - // Set to 'true' when the object is completely initialized. - // This mostly prevents property updates and collisions until the object is completely here. - public bool IsInitialized { get; protected set; } + PrimAssetState = PrimAssetCondition.Unknown; - // Set to 'true' if an object (mesh/linkset/sculpty) is not completely constructed. - // This test is used to prevent some updates to the object when it only partially exists. - // There are several reasons and object might be incomplete: - // Its underlying mesh/sculpty is an asset which must be fetched from the asset store - // It is a linkset who is being added to or removed from - // It is changing state (static to physical, for instance) which requires rebuilding - // This is a computed value based on the underlying physical object construction - abstract public bool IsIncomplete { get; } + // Initialize variables kept in base. + // Beware that these cause taints to be queued whch can cause race conditions on startup. + GravModifier = 1.0f; + Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); + HoverActive = false; - // Return the object mass without calculating it or having side effects - public abstract float RawMass { get; } - // Set the raw mass but also update physical mass properties (inertia, ...) - // 'inWorld' true if the object has already been added to the dynamic world. - public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld); + // Default material type. Also sets Friction, Restitution and Density. + SetMaterial((int)MaterialAttributes.Material.Wood); - // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy. - public virtual OMV.Vector3 Gravity { get; set; } - // The last value calculated for the prim's inertia - public OMV.Vector3 Inertia { get; set; } + CollisionsLastTickStep = -1; - // Reference to the physical body (btCollisionObject) of this object - public BulletBody PhysBody = new BulletBody(0); - // Reference to the physical shape (btCollisionShape) of this object - public BSShape PhysShape = new BSShapeNull(); + SubscribedEventsMs = 0; + // Crazy values that will never be true + CollidingStep = BSScene.NotASimulationStep; + CollidingGroundStep = BSScene.NotASimulationStep; + CollisionAccumulation = BSScene.NotASimulationStep; + ColliderIsMoving = false; + CollisionScore = 0; - // The physical representation of the prim might require an asset fetch. - // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. - public enum PrimAssetCondition - { - Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched - } - public PrimAssetCondition PrimAssetState { get; set; } - public virtual bool AssetFailed() - { - return ( (this.PrimAssetState == PrimAssetCondition.FailedAssetFetch) - || (this.PrimAssetState == PrimAssetCondition.FailedMeshing) ); - } + // All axis free. + LockedLinearAxis = LockedAxisFree; + LockedAngularAxis = LockedAxisFree; + } - // The objects base shape information. Null if not a prim type shape. - public PrimitiveBaseShape BaseShape { get; protected set; } - - // When the physical properties are updated, an EntityProperty holds the update values. - // Keep the current and last EntityProperties to enable computation of differences - // between the current update and the previous values. - public EntityProperties CurrentEntityProperties { get; set; } - public EntityProperties LastEntityProperties { get; set; } - - public virtual OMV.Vector3 Scale { get; set; } - - // It can be confusing for an actor to know if it should move or update an object - // depeneding on the setting of 'selected', 'physical, ... - // This flag is the true test -- if true, the object is being acted on in the physical world - public abstract bool IsPhysicallyActive { get; } - - // Detailed state of the object. - public abstract bool IsSolid { get; } - public abstract bool IsStatic { get; } - public abstract bool IsSelected { get; } - public abstract bool IsVolumeDetect { get; } - - // Materialness - public MaterialAttributes.Material Material { get; private set; } - public override void SetMaterial(int material) - { - Material = (MaterialAttributes.Material)material; - - // Setting the material sets the material attributes also. - // TODO: decide if this is necessary -- the simulator does this. - MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); - Friction = matAttrib.friction; - Restitution = matAttrib.restitution; - Density = matAttrib.density; - // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); - } - - public override float Density - { - get + // Tell the object to clean up. + public virtual void Destroy() { - return base.Density; - } - set - { - DetailLog("{0},BSPhysObject.Density,set,den={1}", LocalID, value); - base.Density = value; - } - } - - // Stop all physical motion. - public abstract void ZeroMotion(bool inTaintTime); - public abstract void ZeroAngularMotion(bool inTaintTime); - - // Update the physical location and motion of the object. Called with data from Bullet. - public abstract void UpdateProperties(EntityProperties entprop); - - // The position value as known by BulletSim. Does not effect the physics engine. - public virtual OMV.Vector3 RawPosition { get; set; } - // Set position in BulletSim and the physics engined to a value immediately. Must be called at taint time. - public abstract OMV.Vector3 ForcePosition { get; set; } - - // The orientation value as known by BulletSim. Does not effect the physics engine. - public virtual OMV.Quaternion RawOrientation { get; set; } - // Set orientation in BulletSim and the physics engine to a value immediately. Must be called at taint time. - public abstract OMV.Quaternion ForceOrientation { get; set; } - - // The velocity value as known by BulletSim. Does not effect the physics engine. - public virtual OMV.Vector3 RawVelocity { get; set; } - // Set velocity in BulletSim and the physics engined to a value immediately. Must be called at taint time. - public abstract OMV.Vector3 ForceVelocity { get; set; } - - // The rotational velocity value as known by BulletSim. Does not effect the physics engine. - public OMV.Vector3 RawRotationalVelocity { get; set; } - - // RawForce is a constant force applied to object (see Force { set; } ) - public OMV.Vector3 RawForce { get; set; } - public OMV.Vector3 RawTorque { get; set; } - - public override void AddAngularForce(OMV.Vector3 force, bool pushforce) - { - AddAngularForce(false, force); - } - public abstract void AddAngularForce(bool inTaintTime, OMV.Vector3 force); - public abstract void AddForce(bool inTaintTime, OMV.Vector3 force); - - // PhysicsActor.Velocity - public override OMV.Vector3 Velocity - { - get { return RawVelocity; } - set - { - // This sets the velocity now. BSCharacter will override to clear target velocity - // before calling this. - RawVelocity = value; - PhysScene.TaintedObject(LocalID, TypeName + ".SetVelocity", delegate () { - // DetailLog("{0},BSPhysObject.Velocity.set,vel={1}", LocalID, RawVelocity); - ForceVelocity = RawVelocity; - }); - } - } - - // PhysicsActor.SetMomentum - // All the physics engines use this as a way of forcing the velocity to something. - // BSCharacter overrides this so it can set the target velocity to zero before calling this. - public override void SetMomentum(OMV.Vector3 momentum) - { - this.Velocity = momentum; - } - - public override OMV.Vector3 RotationalVelocity { - get { - return RawRotationalVelocity; - } - set { - RawRotationalVelocity = value; - Util.ClampV(RawRotationalVelocity, BSParam.MaxAngularVelocity); - // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); - PhysScene.TaintedObject(LocalID, TypeName + ".setRotationalVelocity", delegate() + PhysicalActors.Enable(false); + PhysScene.TaintedObject(LocalID, "BSPhysObject.Destroy", delegate() { - ForceRotationalVelocity = RawRotationalVelocity; + PhysicalActors.Dispose(); }); } - } - public OMV.Vector3 ForceRotationalVelocity { - get { - return RawRotationalVelocity; + + public BSScene PhysScene { get; protected set; } + // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor + public string PhysObjectName { get; protected set; } + public string TypeName { get; protected set; } + + // Set to 'true' when the object is completely initialized. + // This mostly prevents property updates and collisions until the object is completely here. + public bool IsInitialized { get; protected set; } + + // Set to 'true' if an object (mesh/linkset/sculpty) is not completely constructed. + // This test is used to prevent some updates to the object when it only partially exists. + // There are several reasons and object might be incomplete: + // Its underlying mesh/sculpty is an asset which must be fetched from the asset store + // It is a linkset who is being added to or removed from + // It is changing state (static to physical, for instance) which requires rebuilding + // This is a computed value based on the underlying physical object construction + abstract public bool IsIncomplete { get; } + + // Return the object mass without calculating it or having side effects + public abstract float RawMass { get; } + // Set the raw mass but also update physical mass properties (inertia, ...) + // 'inWorld' true if the object has already been added to the dynamic world. + public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld); + + // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy. + public virtual OMV.Vector3 Gravity { get; set; } + // The last value calculated for the prim's inertia + public OMV.Vector3 Inertia { get; set; } + + // Reference to the physical body (btCollisionObject) of this object + public BulletBody PhysBody = new BulletBody(0); + // Reference to the physical shape (btCollisionShape) of this object + public BSShape PhysShape = new BSShapeNull(); + + // The physical representation of the prim might require an asset fetch. + // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'. + public enum PrimAssetCondition + { + Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched } - set { - RawRotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity); + public PrimAssetCondition PrimAssetState { get; set; } + public virtual bool AssetFailed() + { + return ( (this.PrimAssetState == PrimAssetCondition.FailedAssetFetch) + || (this.PrimAssetState == PrimAssetCondition.FailedMeshing) ); + } + + // The objects base shape information. Null if not a prim type shape. + public PrimitiveBaseShape BaseShape { get; protected set; } + + // When the physical properties are updated, an EntityProperty holds the update values. + // Keep the current and last EntityProperties to enable computation of differences + // between the current update and the previous values. + public EntityProperties CurrentEntityProperties { get; set; } + public EntityProperties LastEntityProperties { get; set; } + + public virtual OMV.Vector3 Scale { get; set; } + + // It can be confusing for an actor to know if it should move or update an object + // depeneding on the setting of 'selected', 'physical, ... + // This flag is the true test -- if true, the object is being acted on in the physical world + public abstract bool IsPhysicallyActive { get; } + + // Detailed state of the object. + public abstract bool IsSolid { get; } + public abstract bool IsStatic { get; } + public abstract bool IsSelected { get; } + public abstract bool IsVolumeDetect { get; } + + // Materialness + public MaterialAttributes.Material Material { get; private set; } + public override void SetMaterial(int material) + { + Material = (MaterialAttributes.Material)material; + + // Setting the material sets the material attributes also. + // TODO: decide if this is necessary -- the simulator does this. + MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); + Friction = matAttrib.friction; + Restitution = matAttrib.restitution; + Density = matAttrib.density; + // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); + } + + public override float Density + { + get + { + return base.Density; + } + set + { + DetailLog("{0},BSPhysObject.Density,set,den={1}", LocalID, value); + base.Density = value; + } + } + + // Stop all physical motion. + public abstract void ZeroMotion(bool inTaintTime); + public abstract void ZeroAngularMotion(bool inTaintTime); + + // Update the physical location and motion of the object. Called with data from Bullet. + public abstract void UpdateProperties(EntityProperties entprop); + + // The position value as known by BulletSim. Does not effect the physics engine. + public virtual OMV.Vector3 RawPosition { get; set; } + // Set position in BulletSim and the physics engined to a value immediately. Must be called at taint time. + public abstract OMV.Vector3 ForcePosition { get; set; } + + // The orientation value as known by BulletSim. Does not effect the physics engine. + public virtual OMV.Quaternion RawOrientation { get; set; } + // Set orientation in BulletSim and the physics engine to a value immediately. Must be called at taint time. + public abstract OMV.Quaternion ForceOrientation { get; set; } + + // The velocity value as known by BulletSim. Does not effect the physics engine. + public virtual OMV.Vector3 RawVelocity { get; set; } + // Set velocity in BulletSim and the physics engined to a value immediately. Must be called at taint time. + public abstract OMV.Vector3 ForceVelocity { get; set; } + + // The rotational velocity value as known by BulletSim. Does not effect the physics engine. + public OMV.Vector3 RawRotationalVelocity { get; set; } + + // RawForce is a constant force applied to object (see Force { set; } ) + public OMV.Vector3 RawForce { get; set; } + public OMV.Vector3 RawTorque { get; set; } + + public override void AddAngularForce(OMV.Vector3 force, bool pushforce) + { + AddAngularForce(false, force); + } + public abstract void AddAngularForce(bool inTaintTime, OMV.Vector3 force); + public abstract void AddForce(bool inTaintTime, OMV.Vector3 force); + + // PhysicsActor.Velocity + public override OMV.Vector3 Velocity + { + get { return RawVelocity; } + set + { + // This sets the velocity now. BSCharacter will override to clear target velocity + // before calling this. + RawVelocity = value; + PhysScene.TaintedObject(LocalID, TypeName + ".SetVelocity", delegate () { + // DetailLog("{0},BSPhysObject.Velocity.set,vel={1}", LocalID, RawVelocity); + ForceVelocity = RawVelocity; + }); + } + } + + // PhysicsActor.SetMomentum + // All the physics engines use this as a way of forcing the velocity to something. + // BSCharacter overrides this so it can set the target velocity to zero before calling this. + public override void SetMomentum(OMV.Vector3 momentum) + { + this.Velocity = momentum; + } + + public override OMV.Vector3 RotationalVelocity { + get { + return RawRotationalVelocity; + } + set { + RawRotationalVelocity = value; + Util.ClampV(RawRotationalVelocity, BSParam.MaxAngularVelocity); + // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); + PhysScene.TaintedObject(LocalID, TypeName + ".setRotationalVelocity", delegate() + { + ForceRotationalVelocity = RawRotationalVelocity; + }); + } + } + public OMV.Vector3 ForceRotationalVelocity { + get { + return RawRotationalVelocity; + } + set { + RawRotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity); + if (PhysBody.HasPhysicalBody) + { + DetailLog("{0},{1}.ForceRotationalVel,taint,rotvel={2}", LocalID, TypeName, RawRotationalVelocity); + PhysScene.PE.SetAngularVelocity(PhysBody, RawRotationalVelocity); + // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); + ActivateIfPhysical(false); + } + } + } + + public abstract float ForceBuoyancy { get; set; } + + public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } + + public override bool PIDActive + { + get { return MoveToTargetActive; } + set { MoveToTargetActive = value; } + } + + public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } } + public override float PIDTau { set { MoveToTargetTau = value; } } + + public bool MoveToTargetActive { get; set; } + public OMV.Vector3 MoveToTargetTarget { get; set; } + public float MoveToTargetTau { get; set; } + + // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z + public override bool PIDHoverActive {get {return HoverActive;} set { HoverActive = value; } } + public override float PIDHoverHeight { set { HoverHeight = value; } } + public override PIDHoverType PIDHoverType { set { HoverType = value; } } + public override float PIDHoverTau { set { HoverTau = value; } } + + public bool HoverActive { get; set; } + public float HoverHeight { get; set; } + public PIDHoverType HoverType { get; set; } + public float HoverTau { get; set; } + + // For RotLookAt + public override OMV.Quaternion APIDTarget { set { return; } } + public override bool APIDActive { set { return; } } + public override float APIDStrength { set { return; } } + public override float APIDDamping { set { return; } } + + // The current velocity forward + public virtual float ForwardSpeed + { + get + { + OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation)); + return characterOrientedVelocity.X; + } + } + // The forward speed we are trying to achieve (TargetVelocity) + public virtual float TargetVelocitySpeed + { + get + { + OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation)); + return characterOrientedVelocity.X; + } + } + + // The user can optionally set the center of mass. The user's setting will override any + // computed center-of-mass (like in linksets). + // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass. + public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; } + + public OMV.Vector3 LockedLinearAxis; // zero means locked. one means free. + public OMV.Vector3 LockedAngularAxis; // zero means locked. one means free. + public const float FreeAxis = 1f; + public const float LockedAxis = 0f; + public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free + + // If an axis is locked (flagged above) then the limits of that axis are specified here. + // Linear axis limits are relative to the object's starting coordinates. + // Angular limits are limited to -PI to +PI + public OMV.Vector3 LockedLinearAxisLow; + public OMV.Vector3 LockedLinearAxisHigh; + public OMV.Vector3 LockedAngularAxisLow; + public OMV.Vector3 LockedAngularAxisHigh; + + // Enable physical actions. Bullet will keep sleeping non-moving physical objects so + // they need waking up when parameters are changed. + // Called in taint-time!! + public void ActivateIfPhysical(bool forceIt) + { if (PhysBody.HasPhysicalBody) { - DetailLog("{0},{1}.ForceRotationalVel,taint,rotvel={2}", LocalID, TypeName, RawRotationalVelocity); - PhysScene.PE.SetAngularVelocity(PhysBody, RawRotationalVelocity); - // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity); - ActivateIfPhysical(false); - } - } - } - - public abstract float ForceBuoyancy { get; set; } - - public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } - - public override bool PIDActive - { - get { return MoveToTargetActive; } - set { MoveToTargetActive = value; } - } - - public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } } - public override float PIDTau { set { MoveToTargetTau = value; } } - - public bool MoveToTargetActive { get; set; } - public OMV.Vector3 MoveToTargetTarget { get; set; } - public float MoveToTargetTau { get; set; } - - // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z - public override bool PIDHoverActive {get {return HoverActive;} set { HoverActive = value; } } - public override float PIDHoverHeight { set { HoverHeight = value; } } - public override PIDHoverType PIDHoverType { set { HoverType = value; } } - public override float PIDHoverTau { set { HoverTau = value; } } - - public bool HoverActive { get; set; } - public float HoverHeight { get; set; } - public PIDHoverType HoverType { get; set; } - public float HoverTau { get; set; } - - // For RotLookAt - public override OMV.Quaternion APIDTarget { set { return; } } - public override bool APIDActive { set { return; } } - public override float APIDStrength { set { return; } } - public override float APIDDamping { set { return; } } - - // The current velocity forward - public virtual float ForwardSpeed - { - get - { - OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation)); - return characterOrientedVelocity.X; - } - } - // The forward speed we are trying to achieve (TargetVelocity) - public virtual float TargetVelocitySpeed - { - get - { - OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation)); - return characterOrientedVelocity.X; - } - } - - // The user can optionally set the center of mass. The user's setting will override any - // computed center-of-mass (like in linksets). - // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass. - public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; } - - public OMV.Vector3 LockedLinearAxis; // zero means locked. one means free. - public OMV.Vector3 LockedAngularAxis; // zero means locked. one means free. - public const float FreeAxis = 1f; - public const float LockedAxis = 0f; - public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free - - // If an axis is locked (flagged above) then the limits of that axis are specified here. - // Linear axis limits are relative to the object's starting coordinates. - // Angular limits are limited to -PI to +PI - public OMV.Vector3 LockedLinearAxisLow; - public OMV.Vector3 LockedLinearAxisHigh; - public OMV.Vector3 LockedAngularAxisLow; - public OMV.Vector3 LockedAngularAxisHigh; - - // Enable physical actions. Bullet will keep sleeping non-moving physical objects so - // they need waking up when parameters are changed. - // Called in taint-time!! - public void ActivateIfPhysical(bool forceIt) - { - if (PhysBody.HasPhysicalBody) - { - if (IsPhysical) - { - // Physical objects might need activating - PhysScene.PE.Activate(PhysBody, forceIt); - } - else - { - // Clear the collision cache since we've changed some properties. - PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody); - } - } - } - - // 'actors' act on the physical object to change or constrain its motion. These can range from - // hovering to complex vehicle motion. - // May be called at non-taint time as this just adds the actor to the action list and the real - // work is done during the simulation step. - // Note that, if the actor is already in the list and we are disabling same, the actor is just left - // in the list disabled. - public delegate BSActor CreateActor(); - public void EnableActor(bool enableActor, string actorName, CreateActor creator) - { - lock (PhysicalActors) - { - BSActor theActor; - if (PhysicalActors.TryGetActor(actorName, out theActor)) - { - // The actor already exists so just turn it on or off - DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor); - theActor.Enabled = enableActor; - } - else - { - // The actor does not exist. If it should, create it. - if (enableActor) + if (IsPhysical) { - DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName); - theActor = creator(); - PhysicalActors.Add(actorName, theActor); - theActor.Enabled = true; + // Physical objects might need activating + PhysScene.PE.Activate(PhysBody, forceIt); } else { - DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName); + // Clear the collision cache since we've changed some properties. + PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody); } } } - } - #region Collisions - - // Requested number of milliseconds between collision events. Zero means disabled. - protected int SubscribedEventsMs { get; set; } - // Given subscription, the time that a collision may be passed up - protected int NextCollisionOkTime { get; set; } - // The simulation step that last had a collision - protected long CollidingStep { get; set; } - // The simulation step that last had a collision with the ground - protected long CollidingGroundStep { get; set; } - // The simulation step that last collided with an object - protected long CollidingObjectStep { get; set; } - // The collision flags we think are set in Bullet - protected CollisionFlags CurrentCollisionFlags { get; set; } - // On a collision, check the collider and remember if the last collider was moving - // Used to modify the standing of avatars (avatars on stationary things stand still) - public bool ColliderIsMoving; - // 'true' if the last collider was a volume detect object - public bool ColliderIsVolumeDetect; - // Used by BSCharacter to manage standing (and not slipping) - public bool IsStationary; - - // Count of collisions for this object - protected long CollisionAccumulation { get; set; } - - public override bool IsColliding { - get { return (CollidingStep == PhysScene.SimulationStep); } - set { - if (value) - CollidingStep = PhysScene.SimulationStep; - else - CollidingStep = BSScene.NotASimulationStep; - } - } - // Complex objects (like linksets) need to know if there is a collision on any part of - // their shape. 'IsColliding' has an existing definition of reporting a collision on - // only this specific prim or component of linksets. - // 'HasSomeCollision' is defined as reporting if there is a collision on any part of - // the complex body that this prim is the root of. - public virtual bool HasSomeCollision - { - get { return IsColliding; } - set { IsColliding = value; } - } - public override bool CollidingGround { - get { return (CollidingGroundStep == PhysScene.SimulationStep); } - set + // 'actors' act on the physical object to change or constrain its motion. These can range from + // hovering to complex vehicle motion. + // May be called at non-taint time as this just adds the actor to the action list and the real + // work is done during the simulation step. + // Note that, if the actor is already in the list and we are disabling same, the actor is just left + // in the list disabled. + public delegate BSActor CreateActor(); + public void EnableActor(bool enableActor, string actorName, CreateActor creator) { - if (value) - CollidingGroundStep = PhysScene.SimulationStep; - else - CollidingGroundStep = BSScene.NotASimulationStep; - } - } - public override bool CollidingObj { - get { return (CollidingObjectStep == PhysScene.SimulationStep); } - set { - if (value) - CollidingObjectStep = PhysScene.SimulationStep; - else - CollidingObjectStep = BSScene.NotASimulationStep; - } - } - - // The collisions that have been collected for the next collision reporting (throttled by subscription) - protected CollisionEventUpdate CollisionCollection = new CollisionEventUpdate(); - // This is the collision collection last reported to the Simulator. - public CollisionEventUpdate CollisionsLastReported = new CollisionEventUpdate(); - // Remember the collisions recorded in the last tick for fancy collision checking - // (like a BSCharacter walking up stairs). - public CollisionEventUpdate CollisionsLastTick = new CollisionEventUpdate(); - private long CollisionsLastTickStep = -1; - - // The simulation step is telling this object about a collision. - // I'm the 'collider', the thing I'm colliding with is the 'collidee'. - // Return 'true' if a collision was processed and should be sent up. - // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. - // Called at taint time from within the Step() function - public virtual bool Collide(BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) - { - bool ret = false; - - // if 'collidee' is null, that means it is terrain - uint collideeLocalID = (collidee == null) ? BSScene.TERRAIN_ID : collidee.LocalID; - // All terrain goes by the TERRAIN_ID id when passed up as a collision - if (collideeLocalID <= PhysScene.TerrainManager.HighestTerrainID) { - collideeLocalID = BSScene.TERRAIN_ID; - } - - // The following lines make IsColliding(), CollidingGround() and CollidingObj work - CollidingStep = PhysScene.SimulationStep; - if (collideeLocalID == BSScene.TERRAIN_ID) - { - CollidingGroundStep = PhysScene.SimulationStep; - } - else - { - CollidingObjectStep = PhysScene.SimulationStep; - } - - CollisionAccumulation++; - - // For movement tests, if the collider is me, remember if we are colliding with an object that is moving. - // Here the 'collider'/'collidee' thing gets messed up. In the larger context, when something is checking - // if the thing it is colliding with is moving, for instance, it asks if the its collider is moving. - ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero || collidee.RotationalVelocity != OMV.Vector3.Zero) : false; - ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false; - - - // Make a collection of the collisions that happened the last simulation tick. - // This is different than the collection created for sending up to the simulator as it is cleared every tick. - if (CollisionsLastTickStep != PhysScene.SimulationStep) - { - CollisionsLastTick = new CollisionEventUpdate(); - CollisionsLastTickStep = PhysScene.SimulationStep; - } - CollisionsLastTick.AddCollider(collideeLocalID, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); - - // If someone has subscribed for collision events log the collision so it will be reported up - if (SubscribedEvents()) { - ContactPoint newContact = new ContactPoint(contactPoint, contactNormal, pentrationDepth); - - // Collision sound requires a velocity to know it should happen. This is a lot of computation for a little used feature. - OMV.Vector3 relvel = OMV.Vector3.Zero; - if (IsPhysical) - relvel = RawVelocity; - if (collidee != null && collidee.IsPhysical) - relvel -= collidee.RawVelocity; - newContact.RelativeSpeed = -OMV.Vector3.Dot(relvel, contactNormal); - // DetailLog("{0},{1}.Collision.AddCollider,vel={2},contee.vel={3},relvel={4},relspeed={5}", - // LocalID, TypeName, RawVelocity, (collidee == null ? OMV.Vector3.Zero : collidee.RawVelocity), relvel, newContact.RelativeSpeed); - - lock (PhysScene.CollisionLock) + lock (PhysicalActors) { - CollisionCollection.AddCollider(collideeLocalID, newContact); - } - DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},speed={6},colliderMoving={7}", - LocalID, TypeName, collideeLocalID, contactPoint, contactNormal, pentrationDepth, - newContact.RelativeSpeed, ColliderIsMoving); - - ret = true; - } - return ret; - } - - // Send the collected collisions into the simulator. - // Called at taint time from within the Step() function thus no locking problems - // with CollisionCollection and ObjectsWithNoMoreCollisions. - // Called with BSScene.CollisionLock locked to protect the collision lists. - // Return 'true' if there were some actual collisions passed up - public virtual bool SendCollisions() - { - bool ret = true; - - // If no collisions this call but there were collisions last call, force the collision - // event to be happen right now so quick collision_end. - bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0); - - // throttle the collisions to the number of milliseconds specified in the subscription - if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime)) - { - NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs; - - // We are called if we previously had collisions. If there are no collisions - // this time, send up one last empty event so OpenSim can sense collision end. - if (CollisionCollection.Count == 0) - { - // If I have no collisions this time, remove me from the list of objects with collisions. - ret = false; - } - - DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); - base.SendCollisionUpdate(CollisionCollection); - - // Remember the collisions from this tick for some collision specific processing. - CollisionsLastReported = CollisionCollection; - - // The CollisionCollection instance is passed around in the simulator. - // Make sure we don't have a handle to that one and that a new one is used for next time. - // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, - // a race condition is created for the other users of this instance. - CollisionCollection = new CollisionEventUpdate(); - } - return ret; - } - - // Subscribe for collision events. - // Parameter is the millisecond rate the caller wishes collision events to occur. - public override void SubscribeEvents(int ms) { - // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms); - SubscribedEventsMs = ms; - if (ms > 0) - { - // make sure first collision happens - NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); - - PhysScene.TaintedObject(LocalID, TypeName+".SubscribeEvents", delegate() - { - if (PhysBody.HasPhysicalBody) + BSActor theActor; + if (PhysicalActors.TryGetActor(actorName, out theActor)) { - CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - DetailLog("{0},{1}.SubscribeEvents,setting collision. ms={2}, collisionFlags={3:x}", - LocalID, TypeName, SubscribedEventsMs, CurrentCollisionFlags); + // The actor already exists so just turn it on or off + DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor); + theActor.Enabled = enableActor; } + else + { + // The actor does not exist. If it should, create it. + if (enableActor) + { + DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName); + theActor = creator(); + PhysicalActors.Add(actorName, theActor); + theActor.Enabled = true; + } + else + { + DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName); + } + } + } + } + + #region Collisions + + // Requested number of milliseconds between collision events. Zero means disabled. + protected int SubscribedEventsMs { get; set; } + // Given subscription, the time that a collision may be passed up + protected int NextCollisionOkTime { get; set; } + // The simulation step that last had a collision + protected long CollidingStep { get; set; } + // The simulation step that last had a collision with the ground + protected long CollidingGroundStep { get; set; } + // The simulation step that last collided with an object + protected long CollidingObjectStep { get; set; } + // The collision flags we think are set in Bullet + protected CollisionFlags CurrentCollisionFlags { get; set; } + // On a collision, check the collider and remember if the last collider was moving + // Used to modify the standing of avatars (avatars on stationary things stand still) + public bool ColliderIsMoving; + // 'true' if the last collider was a volume detect object + public bool ColliderIsVolumeDetect; + // Used by BSCharacter to manage standing (and not slipping) + public bool IsStationary; + + // Count of collisions for this object + protected long CollisionAccumulation { get; set; } + + public override bool IsColliding { + get { return (CollidingStep == PhysScene.SimulationStep); } + set { + if (value) + CollidingStep = PhysScene.SimulationStep; + else + CollidingStep = BSScene.NotASimulationStep; + } + } + // Complex objects (like linksets) need to know if there is a collision on any part of + // their shape. 'IsColliding' has an existing definition of reporting a collision on + // only this specific prim or component of linksets. + // 'HasSomeCollision' is defined as reporting if there is a collision on any part of + // the complex body that this prim is the root of. + public virtual bool HasSomeCollision + { + get { return IsColliding; } + set { IsColliding = value; } + } + public override bool CollidingGround { + get { return (CollidingGroundStep == PhysScene.SimulationStep); } + set + { + if (value) + CollidingGroundStep = PhysScene.SimulationStep; + else + CollidingGroundStep = BSScene.NotASimulationStep; + } + } + public override bool CollidingObj { + get { return (CollidingObjectStep == PhysScene.SimulationStep); } + set { + if (value) + CollidingObjectStep = PhysScene.SimulationStep; + else + CollidingObjectStep = BSScene.NotASimulationStep; + } + } + + // The collisions that have been collected for the next collision reporting (throttled by subscription) + protected CollisionEventUpdate CollisionCollection = new CollisionEventUpdate(); + // This is the collision collection last reported to the Simulator. + public CollisionEventUpdate CollisionsLastReported = new CollisionEventUpdate(); + // Remember the collisions recorded in the last tick for fancy collision checking + // (like a BSCharacter walking up stairs). + public CollisionEventUpdate CollisionsLastTick = new CollisionEventUpdate(); + private long CollisionsLastTickStep = -1; + + // The simulation step is telling this object about a collision. + // I'm the 'collider', the thing I'm colliding with is the 'collidee'. + // Return 'true' if a collision was processed and should be sent up. + // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision. + // Called at taint time from within the Step() function + public virtual bool Collide(BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) + { + bool ret = false; + + // if 'collidee' is null, that means it is terrain + uint collideeLocalID = (collidee == null) ? BSScene.TERRAIN_ID : collidee.LocalID; + // All terrain goes by the TERRAIN_ID id when passed up as a collision + if (collideeLocalID <= PhysScene.TerrainManager.HighestTerrainID) { + collideeLocalID = BSScene.TERRAIN_ID; + } + + // The following lines make IsColliding(), CollidingGround() and CollidingObj work + CollidingStep = PhysScene.SimulationStep; + if (collideeLocalID == BSScene.TERRAIN_ID) + { + CollidingGroundStep = PhysScene.SimulationStep; + } + else + { + CollidingObjectStep = PhysScene.SimulationStep; + } + + CollisionAccumulation++; + + // For movement tests, if the collider is me, remember if we are colliding with an object that is moving. + // Here the 'collider'/'collidee' thing gets messed up. In the larger context, when something is checking + // if the thing it is colliding with is moving, for instance, it asks if the its collider is moving. + ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero || collidee.RotationalVelocity != OMV.Vector3.Zero) : false; + ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false; + + + // Make a collection of the collisions that happened the last simulation tick. + // This is different than the collection created for sending up to the simulator as it is cleared every tick. + if (CollisionsLastTickStep != PhysScene.SimulationStep) + { + CollisionsLastTick = new CollisionEventUpdate(); + CollisionsLastTickStep = PhysScene.SimulationStep; + } + CollisionsLastTick.AddCollider(collideeLocalID, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); + + // If someone has subscribed for collision events log the collision so it will be reported up + if (SubscribedEvents()) { + ContactPoint newContact = new ContactPoint(contactPoint, contactNormal, pentrationDepth); + + // Collision sound requires a velocity to know it should happen. This is a lot of computation for a little used feature. + OMV.Vector3 relvel = OMV.Vector3.Zero; + if (IsPhysical) + relvel = RawVelocity; + if (collidee != null && collidee.IsPhysical) + relvel -= collidee.RawVelocity; + newContact.RelativeSpeed = -OMV.Vector3.Dot(relvel, contactNormal); + // DetailLog("{0},{1}.Collision.AddCollider,vel={2},contee.vel={3},relvel={4},relspeed={5}", + // LocalID, TypeName, RawVelocity, (collidee == null ? OMV.Vector3.Zero : collidee.RawVelocity), relvel, newContact.RelativeSpeed); + + lock (PhysScene.CollisionLock) + { + CollisionCollection.AddCollider(collideeLocalID, newContact); + } + DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},speed={6},colliderMoving={7}", + LocalID, TypeName, collideeLocalID, contactPoint, contactNormal, pentrationDepth, + newContact.RelativeSpeed, ColliderIsMoving); + + ret = true; + } + return ret; + } + + // Send the collected collisions into the simulator. + // Called at taint time from within the Step() function thus no locking problems + // with CollisionCollection and ObjectsWithNoMoreCollisions. + // Called with BSScene.CollisionLock locked to protect the collision lists. + // Return 'true' if there were some actual collisions passed up + public virtual bool SendCollisions() + { + bool ret = true; + + // If no collisions this call but there were collisions last call, force the collision + // event to be happen right now so quick collision_end. + bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0); + + // throttle the collisions to the number of milliseconds specified in the subscription + if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime)) + { + NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs; + + // We are called if we previously had collisions. If there are no collisions + // this time, send up one last empty event so OpenSim can sense collision end. + if (CollisionCollection.Count == 0) + { + // If I have no collisions this time, remove me from the list of objects with collisions. + ret = false; + } + + DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); + base.SendCollisionUpdate(CollisionCollection); + + // Remember the collisions from this tick for some collision specific processing. + CollisionsLastReported = CollisionCollection; + + // The CollisionCollection instance is passed around in the simulator. + // Make sure we don't have a handle to that one and that a new one is used for next time. + // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, + // a race condition is created for the other users of this instance. + CollisionCollection = new CollisionEventUpdate(); + } + return ret; + } + + // Subscribe for collision events. + // Parameter is the millisecond rate the caller wishes collision events to occur. + public override void SubscribeEvents(int ms) { + // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms); + SubscribedEventsMs = ms; + if (ms > 0) + { + // make sure first collision happens + NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs); + + PhysScene.TaintedObject(LocalID, TypeName+".SubscribeEvents", delegate() + { + if (PhysBody.HasPhysicalBody) + { + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + DetailLog("{0},{1}.SubscribeEvents,setting collision. ms={2}, collisionFlags={3:x}", + LocalID, TypeName, SubscribedEventsMs, CurrentCollisionFlags); + } + }); + } + else + { + // Subscribing for zero or less is the same as unsubscribing + UnSubscribeEvents(); + } + } + public override void UnSubscribeEvents() { + // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); + SubscribedEventsMs = 0; + PhysScene.TaintedObject(LocalID, TypeName+".UnSubscribeEvents", delegate() + { + // Make sure there is a body there because sometimes destruction happens in an un-ideal order. + if (PhysBody.HasPhysicalBody) + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); }); } - else - { - // Subscribing for zero or less is the same as unsubscribing - UnSubscribeEvents(); + // Return 'true' if the simulator wants collision events + public override bool SubscribedEvents() { + return (SubscribedEventsMs > 0); } - } - public override void UnSubscribeEvents() { - // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName); - SubscribedEventsMs = 0; - PhysScene.TaintedObject(LocalID, TypeName+".UnSubscribeEvents", delegate() + // Because 'CollisionScore' is called many times while sorting, it should not be recomputed + // each time called. So this is built to be light weight for each collision and to do + // all the processing when the user asks for the info. + public void ComputeCollisionScore() { - // Make sure there is a body there because sometimes destruction happens in an un-ideal order. - if (PhysBody.HasPhysicalBody) - CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - }); + // Scale the collision count by the time since the last collision. + // The "+1" prevents dividing by zero. + long timeAgo = PhysScene.SimulationStep - CollidingStep + 1; + CollisionScore = CollisionAccumulation / timeAgo; + } + public override float CollisionScore { get; set; } + + #endregion // Collisions + + #region Per Simulation Step actions + + public BSActorCollection PhysicalActors = new BSActorCollection(); + + // When an update to the physical properties happens, this event is fired to let + // different actors to modify the update before it is passed around + public delegate void PreUpdatePropertyAction(ref EntityProperties entprop); + public event PreUpdatePropertyAction OnPreUpdateProperty; + protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop) + { + PreUpdatePropertyAction actions = OnPreUpdateProperty; + if (actions != null) + actions(ref entprop); + } + + #endregion // Per Simulation Step actions + + // High performance detailed logging routine used by the physical objects. + protected void DetailLog(string msg, params Object[] args) + { + if (PhysScene.PhysicsLogging.Enabled) + PhysScene.DetailLog(msg, args); + } + } - // Return 'true' if the simulator wants collision events - public override bool SubscribedEvents() { - return (SubscribedEventsMs > 0); - } - // Because 'CollisionScore' is called many times while sorting, it should not be recomputed - // each time called. So this is built to be light weight for each collision and to do - // all the processing when the user asks for the info. - public void ComputeCollisionScore() - { - // Scale the collision count by the time since the last collision. - // The "+1" prevents dividing by zero. - long timeAgo = PhysScene.SimulationStep - CollidingStep + 1; - CollisionScore = CollisionAccumulation / timeAgo; - } - public override float CollisionScore { get; set; } - - #endregion // Collisions - - #region Per Simulation Step actions - - public BSActorCollection PhysicalActors = new BSActorCollection(); - - // When an update to the physical properties happens, this event is fired to let - // different actors to modify the update before it is passed around - public delegate void PreUpdatePropertyAction(ref EntityProperties entprop); - public event PreUpdatePropertyAction OnPreUpdateProperty; - protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop) - { - PreUpdatePropertyAction actions = OnPreUpdateProperty; - if (actions != null) - actions(ref entprop); - } - - #endregion // Per Simulation Step actions - - // High performance detailed logging routine used by the physical objects. - protected void DetailLog(string msg, params Object[] args) - { - if (PhysScene.PhysicsLogging.Enabled) - PhysScene.DetailLog(msg, args); - } - -} } diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs index f085d70550..8865a33f16 100644 --- a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs @@ -39,1872 +39,1872 @@ namespace OpenSim.Region.PhysicsModule.BulletS { [Serializable] -public class BSPrim : BSPhysObject -{ - protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private static readonly string LogHeader = "[BULLETS PRIM]"; - - // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. - private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user - - private bool _grabbed; - private bool _isSelected; - private bool _isVolumeDetect; - - private float _mass; // the mass of this object - private OMV.Vector3 _acceleration; - private int _physicsActorType; - private bool _isPhysical; - private bool _flying; - private bool _setAlwaysRun; - private bool _throttleUpdates; - private bool _floatOnWater; - private bool _kinematic; - private float _buoyancy; - - private int CrossingFailures { get; set; } - - // Keep a handle to the vehicle actor so it is easy to set parameters on same. - public const string VehicleActorName = "BasicVehicle"; - - // Parameters for the hover actor - public const string HoverActorName = "BSPrim.HoverActor"; - // Parameters for the axis lock actor - public const String LockedAxisActorName = "BSPrim.LockedAxis"; - // Parameters for the move to target actor - public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor"; - // Parameters for the setForce and setTorque actors - public const string SetForceActorName = "BSPrim.SetForceActor"; - public const string SetTorqueActorName = "BSPrim.SetTorqueActor"; - - public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, - OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) - : base(parent_scene, localID, primName, "BSPrim") + public class BSPrim : BSPhysObject { - // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); - _physicsActorType = (int)ActorTypes.Prim; - RawPosition = pos; - _size = size; - Scale = size; // prims are the size the user wants them to be (different for BSCharactes). - RawOrientation = rotation; - _buoyancy = 0f; - RawVelocity = OMV.Vector3.Zero; - RawRotationalVelocity = OMV.Vector3.Zero; - BaseShape = pbs; - _isPhysical = pisPhysical; - _isVolumeDetect = false; + protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly string LogHeader = "[BULLETS PRIM]"; - _mass = CalculateMass(); + // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. + private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user - DetailLog("{0},BSPrim.constructor,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(pbs)); - // DetailLog("{0},BSPrim.constructor,call", LocalID); - // do the actual object creation at taint time - PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate() + private bool _grabbed; + private bool _isSelected; + private bool _isVolumeDetect; + + private float _mass; // the mass of this object + private OMV.Vector3 _acceleration; + private int _physicsActorType; + private bool _isPhysical; + private bool _flying; + private bool _setAlwaysRun; + private bool _throttleUpdates; + private bool _floatOnWater; + private bool _kinematic; + private float _buoyancy; + + private int CrossingFailures { get; set; } + + // Keep a handle to the vehicle actor so it is easy to set parameters on same. + public const string VehicleActorName = "BasicVehicle"; + + // Parameters for the hover actor + public const string HoverActorName = "BSPrim.HoverActor"; + // Parameters for the axis lock actor + public const String LockedAxisActorName = "BSPrim.LockedAxis"; + // Parameters for the move to target actor + public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor"; + // Parameters for the setForce and setTorque actors + public const string SetForceActorName = "BSPrim.SetForceActor"; + public const string SetTorqueActorName = "BSPrim.SetTorqueActor"; + + public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, + OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) + : base(parent_scene, localID, primName, "BSPrim") { - // Make sure the object is being created with some sanity. - ExtremeSanityCheck(true /* inTaintTime */); + // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); + _physicsActorType = (int)ActorTypes.Prim; + RawPosition = pos; + _size = size; + Scale = size; // prims are the size the user wants them to be (different for BSCharactes). + RawOrientation = rotation; + _buoyancy = 0f; + RawVelocity = OMV.Vector3.Zero; + RawRotationalVelocity = OMV.Vector3.Zero; + BaseShape = pbs; + _isPhysical = pisPhysical; + _isVolumeDetect = false; - CreateGeomAndObject(true); + _mass = CalculateMass(); - CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody); - - IsInitialized = true; - }); - } - - // called when this prim is being destroyed and we should free all the resources - public override void Destroy() - { - // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); - IsInitialized = false; - - base.Destroy(); - - // Undo any vehicle properties - this.VehicleType = (int)Vehicle.TYPE_NONE; - - PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate() - { - DetailLog("{0},BSPrim.Destroy,taint,", LocalID); - // If there are physical body and shape, release my use of same. - PhysScene.Shapes.DereferenceBody(PhysBody, null); - PhysBody.Clear(); - PhysShape.Dereference(PhysScene); - PhysShape = new BSShapeNull(); - }); - } - - // No one uses this property. - public override bool Stopped { - get { return false; } - } - - public override bool IsIncomplete { - get { - return ShapeRebuildScheduled; - } - } - - // 'true' if this object's shape is in need of a rebuild and a rebuild has been queued. - // The prim is still available but its underlying shape will change soon. - // This is protected by a 'lock(this)'. - public bool ShapeRebuildScheduled { get; protected set; } - - public override OMV.Vector3 Size { - get { return _size; } - set { - // We presume the scale and size are the same. If scale must be changed for - // the physical shape, that is done when the geometry is built. - _size = value; - Scale = _size; - ForceBodyShapeRebuild(false); - } - } - - public override PrimitiveBaseShape Shape { - set { - BaseShape = value; - DetailLog("{0},BSPrim.changeShape,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(BaseShape)); - PrimAssetState = PrimAssetCondition.Unknown; - ForceBodyShapeRebuild(false); - } - } - // Cause the body and shape of the prim to be rebuilt if necessary. - // If there are no changes required, this is quick and does not make changes to the prim. - // If rebuilding is necessary (like changing from static to physical), that will happen. - // The 'ShapeRebuildScheduled' tells any checker that the body/shape may change shortly. - // The return parameter is not used by anyone. - public override bool ForceBodyShapeRebuild(bool inTaintTime) - { - if (inTaintTime) - { - // If called in taint time, do the operation immediately - _mass = CalculateMass(); // changing the shape changes the mass - CreateGeomAndObject(true); - } - else - { - lock (this) + DetailLog("{0},BSPrim.constructor,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(pbs)); + // DetailLog("{0},BSPrim.constructor,call", LocalID); + // do the actual object creation at taint time + PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate() { - // If a rebuild is not already in the queue - if (!ShapeRebuildScheduled) + // Make sure the object is being created with some sanity. + ExtremeSanityCheck(true /* inTaintTime */); + + CreateGeomAndObject(true); + + CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody); + + IsInitialized = true; + }); + } + + // called when this prim is being destroyed and we should free all the resources + public override void Destroy() + { + // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); + IsInitialized = false; + + base.Destroy(); + + // Undo any vehicle properties + this.VehicleType = (int)Vehicle.TYPE_NONE; + + PhysScene.TaintedObject(LocalID, "BSPrim.Destroy", delegate() + { + DetailLog("{0},BSPrim.Destroy,taint,", LocalID); + // If there are physical body and shape, release my use of same. + PhysScene.Shapes.DereferenceBody(PhysBody, null); + PhysBody.Clear(); + PhysShape.Dereference(PhysScene); + PhysShape = new BSShapeNull(); + }); + } + + // No one uses this property. + public override bool Stopped { + get { return false; } + } + + public override bool IsIncomplete { + get { + return ShapeRebuildScheduled; + } + } + + // 'true' if this object's shape is in need of a rebuild and a rebuild has been queued. + // The prim is still available but its underlying shape will change soon. + // This is protected by a 'lock(this)'. + public bool ShapeRebuildScheduled { get; protected set; } + + public override OMV.Vector3 Size { + get { return _size; } + set { + // We presume the scale and size are the same. If scale must be changed for + // the physical shape, that is done when the geometry is built. + _size = value; + Scale = _size; + ForceBodyShapeRebuild(false); + } + } + + public override PrimitiveBaseShape Shape { + set { + BaseShape = value; + DetailLog("{0},BSPrim.changeShape,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(BaseShape)); + PrimAssetState = PrimAssetCondition.Unknown; + ForceBodyShapeRebuild(false); + } + } + // Cause the body and shape of the prim to be rebuilt if necessary. + // If there are no changes required, this is quick and does not make changes to the prim. + // If rebuilding is necessary (like changing from static to physical), that will happen. + // The 'ShapeRebuildScheduled' tells any checker that the body/shape may change shortly. + // The return parameter is not used by anyone. + public override bool ForceBodyShapeRebuild(bool inTaintTime) + { + if (inTaintTime) + { + // If called in taint time, do the operation immediately + _mass = CalculateMass(); // changing the shape changes the mass + CreateGeomAndObject(true); + } + else + { + lock (this) { - // Remember that a rebuild is queued -- this is used to flag an incomplete object - ShapeRebuildScheduled = true; - PhysScene.TaintedObject(LocalID, "BSPrim.ForceBodyShapeRebuild", delegate() + // If a rebuild is not already in the queue + if (!ShapeRebuildScheduled) { - _mass = CalculateMass(); // changing the shape changes the mass - CreateGeomAndObject(true); - ShapeRebuildScheduled = false; + // Remember that a rebuild is queued -- this is used to flag an incomplete object + ShapeRebuildScheduled = true; + PhysScene.TaintedObject(LocalID, "BSPrim.ForceBodyShapeRebuild", delegate() + { + _mass = CalculateMass(); // changing the shape changes the mass + CreateGeomAndObject(true); + ShapeRebuildScheduled = false; + }); + } + } + } + return true; + } + public override bool Grabbed { + set { _grabbed = value; + } + } + public override bool Selected { + set + { + if (value != _isSelected) + { + _isSelected = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate() + { + DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); + SetObjectDynamic(false); }); } } } - return true; - } - public override bool Grabbed { - set { _grabbed = value; - } - } - public override bool Selected { - set + public override bool IsSelected { - if (value != _isSelected) + get { return _isSelected; } + } + + public override void CrossingFailure() + { + CrossingFailures++; + if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds) { - _isSelected = value; - PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate() - { - DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); - SetObjectDynamic(false); - }); + base.RaiseOutOfBounds(RawPosition); } - } - } - public override bool IsSelected - { - get { return _isSelected; } - } - - public override void CrossingFailure() - { - CrossingFailures++; - if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds) - { - base.RaiseOutOfBounds(RawPosition); - } - else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds) - { - m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name); - } - return; - } - - // link me to the specified parent - public override void link(PhysicsActor obj) { - } - - // delink me from my linkset - public override void delink() { - } - - // Set motion values to zero. - // Do it to the properties so the values get set in the physics engine. - // Push the setting of the values to the viewer. - // Called at taint time! - public override void ZeroMotion(bool inTaintTime) - { - RawVelocity = OMV.Vector3.Zero; - _acceleration = OMV.Vector3.Zero; - RawRotationalVelocity = OMV.Vector3.Zero; - - // Zero some other properties in the physics engine - PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate() - { - if (PhysBody.HasPhysicalBody) - PhysScene.PE.ClearAllForces(PhysBody); - }); - } - public override void ZeroAngularMotion(bool inTaintTime) - { - RawRotationalVelocity = OMV.Vector3.Zero; - // Zero some other properties in the physics engine - PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate() - { - // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); - if (PhysBody.HasPhysicalBody) + else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds) { - PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, RawRotationalVelocity); - PhysScene.PE.SetAngularVelocity(PhysBody, RawRotationalVelocity); + m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name); } - }); - } - - public override void LockAngularMotion(byte axislocks) - { - DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axislocks); - - ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f); - if ((axislocks & 0x02) != 0) - { - ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X, 0f, 0f); - } - if ((axislocks & 0x04) != 0) - { - ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y, 0f, 0f); - } - if ((axislocks & 0x08) != 0) - { - ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z, 0f, 0f); - } - - InitializeAxisActor(); - - return; - } - - public override OMV.Vector3 Position { - get { - // don't do the GetObjectPosition for root elements because this function is called a zillion times. - // RawPosition = ForcePosition; - return RawPosition; - } - set { - // If the position must be forced into the physics engine, use ForcePosition. - // All positions are given in world positions. - if (RawPosition == value) - { - DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); - return; - } - RawPosition = value; - PositionSanityCheck(false); - - PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate() - { - DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); - ForcePosition = RawPosition; - }); - } - } - - // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity. - public override OMV.Vector3 ForcePosition { - get { - RawPosition = PhysScene.PE.GetPosition(PhysBody); - return RawPosition; - } - set { - RawPosition = value; - if (PhysBody.HasPhysicalBody) - { - PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); - ActivateIfPhysical(false); - } - } - } - - // Check that the current position is sane and, if not, modify the position to make it so. - // Check for being below terrain and being out of bounds. - // Returns 'true' of the position was made sane by some action. - private bool PositionSanityCheck(bool inTaintTime) - { - bool ret = false; - - // We don't care where non-physical items are placed - if (!IsPhysicallyActive) - return ret; - - if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) - { - // The physical object is out of the known/simulated area. - // Upper levels of code will handle the transition to other areas so, for - // the time, we just ignore the position. - return ret; - } - - float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); - OMV.Vector3 upForce = OMV.Vector3.Zero; - float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); - if ((RawPosition.Z + approxSize / 2f) < terrainHeight) - { - DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); - float targetHeight = terrainHeight + (Size.Z / 2f); - // If the object is below ground it just has to be moved up because pushing will - // not get it through the terrain - RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight); - if (inTaintTime) - { - ForcePosition = RawPosition; - } - // If we are throwing the object around, zero its other forces - ZeroMotion(inTaintTime); - ret = true; - } - - if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) - { - float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); - // TODO: a floating motor so object will bob in the water - if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) - { - // Upforce proportional to the distance away from the water. Correct the error in 1 sec. - upForce.Z = (waterHeight - RawPosition.Z) * 1f; - - // Apply upforce and overcome gravity. - OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity; - DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce); - AddForce(inTaintTime, correctionForce); - ret = true; - } - } - - return ret; - } - - // Occasionally things will fly off and really get lost. - // Find the wanderers and bring them back. - // Return 'true' if some parameter need some sanity. - private bool ExtremeSanityCheck(bool inTaintTime) - { - bool ret = false; - - int wayOverThere = -1000; - int wayOutThere = 10000; - // There have been instances of objects getting thrown way out of bounds and crashing - // the border crossing code. - if ( RawPosition.X < wayOverThere || RawPosition.X > wayOutThere - || RawPosition.Y < wayOverThere || RawPosition.X > wayOutThere - || RawPosition.Z < wayOverThere || RawPosition.X > wayOutThere) - { - RawPosition = new OMV.Vector3(10, 10, 50); - ZeroMotion(inTaintTime); - ret = true; - } - if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocitySquared) - { - RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity); - ret = true; - } - if (RawRotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) - { - RawRotationalVelocity = Util.ClampV(RawRotationalVelocity, BSParam.MaxAngularVelocity); - ret = true; - } - - return ret; - } - - // Return the effective mass of the object. - // The definition of this call is to return the mass of the prim. - // If the simulator cares about the mass of the linkset, it will sum it itself. - public override float Mass - { - get { return _mass; } - } - // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code) - public virtual float TotalMass - { - get { return _mass; } - } - // used when we only want this prim's mass and not the linkset thing - public override float RawMass { - get { return _mass; } - } - // Set the physical mass to the passed mass. - // Note that this does not change _mass! - public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) - { - if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) - { - if (IsStatic) - { - PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity); - Inertia = OMV.Vector3.Zero; - PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia); - PhysScene.PE.UpdateInertiaTensor(PhysBody); - } - else - { - if (inWorld) - { - // Changing interesting properties doesn't change proxy and collision cache - // information. The Bullet solution is to re-add the object to the world - // after parameters are changed. - PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); - } - - // The computation of mass props requires gravity to be set on the object. - Gravity = ComputeGravity(Buoyancy); - PhysScene.PE.SetGravity(PhysBody, Gravity); - - // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG - // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG - - Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); - PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia); - PhysScene.PE.UpdateInertiaTensor(PhysBody); - - DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", - LocalID, physMass, Inertia, Gravity, inWorld); - - if (inWorld) - { - AddObjectToPhysicalWorld(); - } - } - } - } - - // Return what gravity should be set to this very moment - public OMV.Vector3 ComputeGravity(float buoyancy) - { - OMV.Vector3 ret = PhysScene.DefaultGravity; - - if (!IsStatic) - { - ret *= (1f - buoyancy); - ret *= GravModifier; - } - - return ret; - } - - // Is this used? - public override OMV.Vector3 CenterOfMass - { - get { return RawPosition; } - } - - // Is this used? - public override OMV.Vector3 GeometricCenter - { - get { return RawPosition; } - } - - public override OMV.Vector3 Force { - get { return RawForce; } - set { - RawForce = value; - EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate() - { - return new BSActorSetForce(PhysScene, this, SetForceActorName); - }); - - // Call update so actor Refresh() is called to start things off - PhysScene.TaintedObject(LocalID, "BSPrim.setForce", delegate() - { - UpdatePhysicalParameters(); - }); - } - } - - // Find and return a handle to the current vehicle actor. - // Return 'null' if there is no vehicle actor. - public BSDynamics GetVehicleActor(bool createIfNone) - { - BSDynamics ret = null; - BSActor actor; - if (PhysicalActors.TryGetActor(VehicleActorName, out actor)) - { - ret = actor as BSDynamics; - } - else - { - if (createIfNone) - { - ret = new BSDynamics(PhysScene, this, VehicleActorName); - PhysicalActors.Add(ret.ActorName, ret); - } - } - return ret; - } - - public override int VehicleType { - get { - int ret = (int)Vehicle.TYPE_NONE; - BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); - if (vehicleActor != null) - ret = (int)vehicleActor.Type; - return ret; - } - set { - Vehicle type = (Vehicle)value; - - PhysScene.TaintedObject(LocalID, "setVehicleType", delegate() - { - // Some vehicle scripts change vehicle type on the fly as an easy way to - // change all the parameters. Like a plane changing to CAR when on the - // ground. In this case, don't want to zero motion. - // ZeroMotion(true /* inTaintTime */); - if (type == Vehicle.TYPE_NONE) - { - // Vehicle type is 'none' so get rid of any actor that may have been allocated. - BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); - if (vehicleActor != null) - { - PhysicalActors.RemoveAndRelease(vehicleActor.ActorName); - } - } - else - { - // Vehicle type is not 'none' so create an actor and set it running. - BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); - if (vehicleActor != null) - { - vehicleActor.ProcessTypeChange(type); - ActivateIfPhysical(false); - } - } - }); - } - } - public override void VehicleFloatParam(int param, float value) - { - PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate() - { - BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); - if (vehicleActor != null) - { - vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); - ActivateIfPhysical(false); - } - }); - } - public override void VehicleVectorParam(int param, OMV.Vector3 value) - { - PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate() - { - BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); - if (vehicleActor != null) - { - vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); - ActivateIfPhysical(false); - } - }); - } - public override void VehicleRotationParam(int param, OMV.Quaternion rotation) - { - PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate() - { - BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); - if (vehicleActor != null) - { - vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); - ActivateIfPhysical(false); - } - }); - } - public override void VehicleFlags(int param, bool remove) - { - PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate() - { - BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); - if (vehicleActor != null) - { - vehicleActor.ProcessVehicleFlags(param, remove); - } - }); - } - - public override void SetVehicle(object pvdata) - { - PhysScene.TaintedObject(LocalID, "BSPrim.SetVehicle", delegate () - { - BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); - if (vehicleActor != null && (pvdata is VehicleData) ) - { - VehicleData vdata = (VehicleData)pvdata; - // vehicleActor.ProcessSetVehicle((VehicleData)vdata); - - vehicleActor.ProcessTypeChange(vdata.m_type); - vehicleActor.ProcessVehicleFlags(-1, false); - vehicleActor.ProcessVehicleFlags((int)vdata.m_flags, false); - - // Linear properties - vehicleActor.ProcessVectorVehicleParam(Vehicle.LINEAR_MOTOR_DIRECTION, vdata.m_linearMotorDirection); - vehicleActor.ProcessVectorVehicleParam(Vehicle.LINEAR_FRICTION_TIMESCALE, vdata.m_linearFrictionTimescale); - vehicleActor.ProcessFloatVehicleParam(Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE, vdata.m_linearMotorDecayTimescale); - vehicleActor.ProcessFloatVehicleParam(Vehicle.LINEAR_MOTOR_TIMESCALE, vdata.m_linearMotorTimescale); - vehicleActor.ProcessVectorVehicleParam(Vehicle.LINEAR_MOTOR_OFFSET, vdata.m_linearMotorOffset); - - //Angular properties - vehicleActor.ProcessVectorVehicleParam(Vehicle.ANGULAR_MOTOR_DIRECTION, vdata.m_angularMotorDirection); - vehicleActor.ProcessFloatVehicleParam(Vehicle.ANGULAR_MOTOR_TIMESCALE, vdata.m_angularMotorTimescale); - vehicleActor.ProcessFloatVehicleParam(Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE, vdata.m_angularMotorDecayTimescale); - vehicleActor.ProcessVectorVehicleParam(Vehicle.ANGULAR_FRICTION_TIMESCALE, vdata.m_angularFrictionTimescale); - - //Deflection properties - vehicleActor.ProcessFloatVehicleParam(Vehicle.ANGULAR_DEFLECTION_EFFICIENCY, vdata.m_angularDeflectionEfficiency); - vehicleActor.ProcessFloatVehicleParam(Vehicle.ANGULAR_DEFLECTION_TIMESCALE, vdata.m_angularDeflectionTimescale); - vehicleActor.ProcessFloatVehicleParam(Vehicle.LINEAR_DEFLECTION_EFFICIENCY, vdata.m_linearDeflectionEfficiency); - vehicleActor.ProcessFloatVehicleParam(Vehicle.LINEAR_DEFLECTION_TIMESCALE, vdata.m_linearDeflectionTimescale); - - //Banking properties - vehicleActor.ProcessFloatVehicleParam(Vehicle.BANKING_EFFICIENCY, vdata.m_bankingEfficiency); - vehicleActor.ProcessFloatVehicleParam(Vehicle.BANKING_MIX, vdata.m_bankingMix); - vehicleActor.ProcessFloatVehicleParam(Vehicle.BANKING_TIMESCALE, vdata.m_bankingTimescale); - - //Hover and Buoyancy properties - vehicleActor.ProcessFloatVehicleParam(Vehicle.HOVER_HEIGHT, vdata.m_VhoverHeight); - vehicleActor.ProcessFloatVehicleParam(Vehicle.HOVER_EFFICIENCY, vdata.m_VhoverEfficiency); - vehicleActor.ProcessFloatVehicleParam(Vehicle.HOVER_TIMESCALE, vdata.m_VhoverTimescale); - vehicleActor.ProcessFloatVehicleParam(Vehicle.BUOYANCY, vdata.m_VehicleBuoyancy); - - //Attractor properties - vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, vdata.m_verticalAttractionEfficiency); - vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, vdata.m_verticalAttractionTimescale); - - vehicleActor.ProcessRotationVehicleParam(Vehicle.REFERENCE_FRAME, vdata.m_referenceFrame); - } - }); - } - - // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more - public override void SetVolumeDetect(int param) { - bool newValue = (param != 0); - if (_isVolumeDetect != newValue) - { - _isVolumeDetect = newValue; - PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate() - { - // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); - SetObjectDynamic(true); - }); - } - return; - } - public override bool IsVolumeDetect - { - get { return _isVolumeDetect; } - } - public override void SetMaterial(int material) - { - base.SetMaterial(material); - PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate() - { - UpdatePhysicalParameters(); - }); - } - public override float Friction - { - get { return base.Friction; } - set - { - if (base.Friction != value) - { - base.Friction = value; - PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate() - { - UpdatePhysicalParameters(); - }); - } - } - } - public override float Restitution - { - get { return base.Restitution; } - set - { - if (base.Restitution != value) - { - base.Restitution = value; - PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate() - { - UpdatePhysicalParameters(); - }); - } - } - } - // The simulator/viewer keep density as 100kg/m3. - // Remember to use BSParam.DensityScaleFactor to create the physical density. - public override float Density - { - get { return base.Density; } - set - { - if (base.Density != value) - { - base.Density = value; - PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate() - { - UpdatePhysicalParameters(); - }); - } - } - } - public override float GravModifier - { - get { return base.GravModifier; } - set - { - if (base.GravModifier != value) - { - base.GravModifier = value; - PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate() - { - UpdatePhysicalParameters(); - }); - } - } - } - public override OMV.Vector3 ForceVelocity { - get { return RawVelocity; } - set { - RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); - if (PhysBody.HasPhysicalBody) - { - DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity); - PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); - ActivateIfPhysical(false); - } - } - } - public override OMV.Vector3 Torque { - get { return RawTorque; } - set { - RawTorque = value; - EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate() - { - return new BSActorSetTorque(PhysScene, this, SetTorqueActorName); - }); - DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); - - // Call update so actor Refresh() is called to start things off - PhysScene.TaintedObject(LocalID, "BSPrim.setTorque", delegate() - { - UpdatePhysicalParameters(); - }); - } - } - public override OMV.Vector3 Acceleration { - get { return _acceleration; } - set { _acceleration = value; } - } - - public override OMV.Quaternion Orientation { - get { - return RawOrientation; - } - set { - if (RawOrientation == value) - return; - RawOrientation = value; - - PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate() - { - ForceOrientation = RawOrientation; - }); - } - } - // Go directly to Bullet to get/set the value. - public override OMV.Quaternion ForceOrientation - { - get - { - RawOrientation = PhysScene.PE.GetOrientation(PhysBody); - return RawOrientation; - } - set - { - RawOrientation = value; - if (PhysBody.HasPhysicalBody) - PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); - } - } - public override int PhysicsActorType { - get { return _physicsActorType; } - set { _physicsActorType = value; } - } - public override bool IsPhysical { - get { return _isPhysical; } - set { - if (_isPhysical != value) - { - _isPhysical = value; - PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate() - { - DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); - SetObjectDynamic(true); - // whether phys-to-static or static-to-phys, the object is not moving. - ZeroMotion(true); - - }); - } - } - } - - // An object is static (does not move) if selected or not physical - public override bool IsStatic - { - get { return _isSelected || !IsPhysical; } - } - - // An object is solid if it's not phantom and if it's not doing VolumeDetect - public override bool IsSolid - { - get { return !IsPhantom && !_isVolumeDetect; } - } - - // The object is moving and is actively being dynamic in the physical world - public override bool IsPhysicallyActive - { - get { return !_isSelected && IsPhysical; } - } - - // Make gravity work if the object is physical and not selected - // Called at taint-time!! - private void SetObjectDynamic(bool forceRebuild) - { - // Recreate the physical object if necessary - CreateGeomAndObject(forceRebuild); - } - - // Convert the simulator's physical properties into settings on BulletSim objects. - // There are four flags we're interested in: - // IsStatic: Object does not move, otherwise the object has mass and moves - // isSolid: other objects bounce off of this object - // isVolumeDetect: other objects pass through but can generate collisions - // collisionEvents: whether this object returns collision events - // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters. - public virtual void UpdatePhysicalParameters() - { - if (!PhysBody.HasPhysicalBody) - { - // This would only happen if updates are called for during initialization when the body is not set up yet. - // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); return; } - // Mangling all the physical properties requires the object not be in the physical world. - // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). - PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); + // link me to the specified parent + public override void link(PhysicsActor obj) { + } - // Set up the object physicalness (does gravity and collisions move this object) - MakeDynamic(IsStatic); + // delink me from my linkset + public override void delink() { + } - // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) - PhysicalActors.Refresh(); - - // Arrange for collision events if the simulator wants them - EnableCollisions(SubscribedEvents()); - - // Make solid or not (do things bounce off or pass through this object). - MakeSolid(IsSolid); - - AddObjectToPhysicalWorld(); - - // Rebuild its shape - PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); - - DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", - LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), - CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); - } - - // "Making dynamic" means changing to and from static. - // When static, gravity does not effect the object and it is fixed in space. - // When dynamic, the object can fall and be pushed by others. - // This is independent of its 'solidness' which controls what passes through - // this object and what interacts with it. - protected virtual void MakeDynamic(bool makeStatic) - { - if (makeStatic) + // Set motion values to zero. + // Do it to the properties so the values get set in the physics engine. + // Push the setting of the values to the viewer. + // Called at taint time! + public override void ZeroMotion(bool inTaintTime) { - // Become a Bullet 'static' object type - CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); - // Stop all movement - ZeroMotion(true); + RawVelocity = OMV.Vector3.Zero; + _acceleration = OMV.Vector3.Zero; + RawRotationalVelocity = OMV.Vector3.Zero; - // Set various physical properties so other object interact properly - PhysScene.PE.SetFriction(PhysBody, Friction); - PhysScene.PE.SetRestitution(PhysBody, Restitution); - PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); - - // Mass is zero which disables a bunch of physics stuff in Bullet - UpdatePhysicalMassProperties(0f, false); - // Set collision detection parameters - if (BSParam.CcdMotionThreshold > 0f) - { - PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); - PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); - } - - // The activation state is 'disabled' so Bullet will not try to act on it. - // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); - // Start it out sleeping and physical actions could wake it up. - PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); - - // This collides like a static object - PhysBody.collisionType = CollisionType.Static; - } - else - { - // Not a Bullet static object - CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); - - // Set various physical properties so other object interact properly - PhysScene.PE.SetFriction(PhysBody, Friction); - PhysScene.PE.SetRestitution(PhysBody, Restitution); - // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); - - // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 - // Since this can be called multiple times, only zero forces when becoming physical - // PhysicsScene.PE.ClearAllForces(BSBody); - - // For good measure, make sure the transform is set through to the motion state - ForcePosition = RawPosition; - ForceVelocity = RawVelocity; - ForceRotationalVelocity = RawRotationalVelocity; - - // A dynamic object has mass - UpdatePhysicalMassProperties(RawMass, false); - - // Set collision detection parameters - if (BSParam.CcdMotionThreshold > 0f) - { - PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); - PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); - } - - // Various values for simulation limits - PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); - PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); - PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); - PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); - - // This collides like an object. - PhysBody.collisionType = CollisionType.Dynamic; - - // Force activation of the object so Bullet will act on it. - // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. - PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); - } - } - - // "Making solid" means that other object will not pass through this object. - // To make transparent, we create a Bullet ghost object. - // Note: This expects to be called from the UpdatePhysicalParameters() routine as - // the functions after this one set up the state of a possibly newly created collision body. - private void MakeSolid(bool makeSolid) - { - CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody); - if (makeSolid) - { - // Verify the previous code created the correct shape for this type of thing. - if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0) - { - m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); - } - CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); - } - else - { - if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0) - { - m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); - } - CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); - - // Change collision info from a static object to a ghosty collision object - PhysBody.collisionType = CollisionType.VolumeDetect; - } - } - - // Turn on or off the flag controlling whether collision events are returned to the simulator. - private void EnableCollisions(bool wantsCollisionEvents) - { - if (wantsCollisionEvents) - { - CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - } - else - { - CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); - } - } - - // Add me to the physical world. - // Object MUST NOT already be in the world. - // This routine exists because some assorted properties get mangled by adding to the world. - internal void AddObjectToPhysicalWorld() - { - if (PhysBody.HasPhysicalBody) - { - PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); - } - else - { - m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID); - DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType); - } - } - - // prims don't fly - public override bool Flying { - get { return _flying; } - set { - _flying = value; - } - } - public override bool SetAlwaysRun { - get { return _setAlwaysRun; } - set { _setAlwaysRun = value; } - } - public override bool ThrottleUpdates { - get { return _throttleUpdates; } - set { _throttleUpdates = value; } - } - public bool IsPhantom { - get { - // SceneObjectPart removes phantom objects from the physics scene - // so, although we could implement touching and such, we never - // are invoked as a phantom object - return false; - } - } - public override bool FloatOnWater { - set { - _floatOnWater = value; - PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate() - { - if (_floatOnWater) - CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); - else - CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); - }); - } - } - public override bool Kinematic { - get { return _kinematic; } - set { _kinematic = value; - // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); - } - } - public override float Buoyancy { - get { return _buoyancy; } - set { - _buoyancy = value; - PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate() - { - ForceBuoyancy = _buoyancy; - }); - } - } - public override float ForceBuoyancy { - get { return _buoyancy; } - set { - _buoyancy = value; - // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); - // Force the recalculation of the various inertia,etc variables in the object - UpdatePhysicalMassProperties(RawMass, true); - DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity); - ActivateIfPhysical(false); - } - } - - public override bool PIDActive - { - get - { - return MoveToTargetActive; - } - - set - { - MoveToTargetActive = value; - - EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate() - { - return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName); - }); - - // Call update so actor Refresh() is called to start things off - PhysScene.TaintedObject(LocalID, "BSPrim.PIDActive", delegate() - { - UpdatePhysicalParameters(); - }); - } - } - - public override OMV.Vector3 PIDTarget - { - set - { - base.PIDTarget = value; - BSActor actor; - if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor)) - { - // if the actor exists, tell it to refresh its values. - actor.Refresh(); - } - - } - } - // Used for llSetHoverHeight and maybe vehicle height - // Hover Height will override MoveTo target's Z - public override bool PIDHoverActive { - get - { - return base.HoverActive; - } - set { - base.HoverActive = value; - EnableActor(HoverActive, HoverActorName, delegate() - { - return new BSActorHover(PhysScene, this, HoverActorName); - }); - - // Call update so actor Refresh() is called to start things off - PhysScene.TaintedObject(LocalID, "BSPrim.PIDHoverActive", delegate() - { - UpdatePhysicalParameters(); - }); - } - } - - public override void AddForce(OMV.Vector3 force, bool pushforce) { - // Per documentation, max force is limited. - OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); - - // Push forces seem to be scaled differently (follow pattern in ubODE) - if (!pushforce) { - // Since this force is being applied in only one step, make this a force per second. - addForce /= PhysScene.LastTimeStep; - } - - AddForce(false /* inTaintTime */, addForce); - } - - // Applying a force just adds this to the total force on the object. - // This added force will only last the next simulation tick. - public override void AddForce(bool inTaintTime, OMV.Vector3 force) { - // for an object, doesn't matter if force is a pushforce or not - if (IsPhysicallyActive) - { - if (force.IsFinite()) - { - // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); - - OMV.Vector3 addForce = force; - PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate() - { - // Bullet adds this central force to the total force for this tick. - // Deep down in Bullet: - // linearVelocity += totalForce / mass * timeStep; - DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); - if (PhysBody.HasPhysicalBody) - { - PhysScene.PE.ApplyCentralForce(PhysBody, addForce); - ActivateIfPhysical(false); - } - }); - } - else - { - m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); - return; - } - } - } - - public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) { - // for an object, doesn't matter if force is a pushforce or not - if (!IsPhysicallyActive) - { - if (impulse.IsFinite()) - { - OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); - // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); - - PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate() - { - // Bullet adds this impulse immediately to the velocity - DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); - if (PhysBody.HasPhysicalBody) - { - PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); - ActivateIfPhysical(false); - } - }); - } - else - { - m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID); - return; - } - } - } - - // BSPhysObject.AddAngularForce() - public override void AddAngularForce(bool inTaintTime, OMV.Vector3 force) - { - if (force.IsFinite()) - { - OMV.Vector3 angForce = force; - PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate() + // Zero some other properties in the physics engine + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate() { + if (PhysBody.HasPhysicalBody) + PhysScene.PE.ClearAllForces(PhysBody); + }); + } + public override void ZeroAngularMotion(bool inTaintTime) + { + RawRotationalVelocity = OMV.Vector3.Zero; + // Zero some other properties in the physics engine + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate() + { + // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); if (PhysBody.HasPhysicalBody) { - DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); - PhysScene.PE.ApplyTorque(PhysBody, angForce); + PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, RawRotationalVelocity); + PhysScene.PE.SetAngularVelocity(PhysBody, RawRotationalVelocity); + } + }); + } + + public override void LockAngularMotion(byte axislocks) + { + DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axislocks); + + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f); + if ((axislocks & 0x02) != 0) + { + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X, 0f, 0f); + } + if ((axislocks & 0x04) != 0) + { + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y, 0f, 0f); + } + if ((axislocks & 0x08) != 0) + { + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z, 0f, 0f); + } + + InitializeAxisActor(); + + return; + } + + public override OMV.Vector3 Position { + get { + // don't do the GetObjectPosition for root elements because this function is called a zillion times. + // RawPosition = ForcePosition; + return RawPosition; + } + set { + // If the position must be forced into the physics engine, use ForcePosition. + // All positions are given in world positions. + if (RawPosition == value) + { + DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); + return; + } + RawPosition = value; + PositionSanityCheck(false); + + PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate() + { + DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); + ForcePosition = RawPosition; + }); + } + } + + // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity. + public override OMV.Vector3 ForcePosition { + get { + RawPosition = PhysScene.PE.GetPosition(PhysBody); + return RawPosition; + } + set { + RawPosition = value; + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); + ActivateIfPhysical(false); + } + } + } + + // Check that the current position is sane and, if not, modify the position to make it so. + // Check for being below terrain and being out of bounds. + // Returns 'true' of the position was made sane by some action. + private bool PositionSanityCheck(bool inTaintTime) + { + bool ret = false; + + // We don't care where non-physical items are placed + if (!IsPhysicallyActive) + return ret; + + if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) + { + // The physical object is out of the known/simulated area. + // Upper levels of code will handle the transition to other areas so, for + // the time, we just ignore the position. + return ret; + } + + float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); + OMV.Vector3 upForce = OMV.Vector3.Zero; + float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z)); + if ((RawPosition.Z + approxSize / 2f) < terrainHeight) + { + DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); + float targetHeight = terrainHeight + (Size.Z / 2f); + // If the object is below ground it just has to be moved up because pushing will + // not get it through the terrain + RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight); + if (inTaintTime) + { + ForcePosition = RawPosition; + } + // If we are throwing the object around, zero its other forces + ZeroMotion(inTaintTime); + ret = true; + } + + if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) + { + float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); + // TODO: a floating motor so object will bob in the water + if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) + { + // Upforce proportional to the distance away from the water. Correct the error in 1 sec. + upForce.Z = (waterHeight - RawPosition.Z) * 1f; + + // Apply upforce and overcome gravity. + OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity; + DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce); + AddForce(inTaintTime, correctionForce); + ret = true; + } + } + + return ret; + } + + // Occasionally things will fly off and really get lost. + // Find the wanderers and bring them back. + // Return 'true' if some parameter need some sanity. + private bool ExtremeSanityCheck(bool inTaintTime) + { + bool ret = false; + + int wayOverThere = -1000; + int wayOutThere = 10000; + // There have been instances of objects getting thrown way out of bounds and crashing + // the border crossing code. + if ( RawPosition.X < wayOverThere || RawPosition.X > wayOutThere + || RawPosition.Y < wayOverThere || RawPosition.X > wayOutThere + || RawPosition.Z < wayOverThere || RawPosition.X > wayOutThere) + { + RawPosition = new OMV.Vector3(10, 10, 50); + ZeroMotion(inTaintTime); + ret = true; + } + if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocitySquared) + { + RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity); + ret = true; + } + if (RawRotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) + { + RawRotationalVelocity = Util.ClampV(RawRotationalVelocity, BSParam.MaxAngularVelocity); + ret = true; + } + + return ret; + } + + // Return the effective mass of the object. + // The definition of this call is to return the mass of the prim. + // If the simulator cares about the mass of the linkset, it will sum it itself. + public override float Mass + { + get { return _mass; } + } + // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code) + public virtual float TotalMass + { + get { return _mass; } + } + // used when we only want this prim's mass and not the linkset thing + public override float RawMass { + get { return _mass; } + } + // Set the physical mass to the passed mass. + // Note that this does not change _mass! + public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) + { + if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) + { + if (IsStatic) + { + PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity); + Inertia = OMV.Vector3.Zero; + PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia); + PhysScene.PE.UpdateInertiaTensor(PhysBody); + } + else + { + if (inWorld) + { + // Changing interesting properties doesn't change proxy and collision cache + // information. The Bullet solution is to re-add the object to the world + // after parameters are changed. + PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); + } + + // The computation of mass props requires gravity to be set on the object. + Gravity = ComputeGravity(Buoyancy); + PhysScene.PE.SetGravity(PhysBody, Gravity); + + // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG + // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG + + Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); + PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia); + PhysScene.PE.UpdateInertiaTensor(PhysBody); + + DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", + LocalID, physMass, Inertia, Gravity, inWorld); + + if (inWorld) + { + AddObjectToPhysicalWorld(); + } + } + } + } + + // Return what gravity should be set to this very moment + public OMV.Vector3 ComputeGravity(float buoyancy) + { + OMV.Vector3 ret = PhysScene.DefaultGravity; + + if (!IsStatic) + { + ret *= (1f - buoyancy); + ret *= GravModifier; + } + + return ret; + } + + // Is this used? + public override OMV.Vector3 CenterOfMass + { + get { return RawPosition; } + } + + // Is this used? + public override OMV.Vector3 GeometricCenter + { + get { return RawPosition; } + } + + public override OMV.Vector3 Force { + get { return RawForce; } + set { + RawForce = value; + EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate() + { + return new BSActorSetForce(PhysScene, this, SetForceActorName); + }); + + // Call update so actor Refresh() is called to start things off + PhysScene.TaintedObject(LocalID, "BSPrim.setForce", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + + // Find and return a handle to the current vehicle actor. + // Return 'null' if there is no vehicle actor. + public BSDynamics GetVehicleActor(bool createIfNone) + { + BSDynamics ret = null; + BSActor actor; + if (PhysicalActors.TryGetActor(VehicleActorName, out actor)) + { + ret = actor as BSDynamics; + } + else + { + if (createIfNone) + { + ret = new BSDynamics(PhysScene, this, VehicleActorName); + PhysicalActors.Add(ret.ActorName, ret); + } + } + return ret; + } + + public override int VehicleType { + get { + int ret = (int)Vehicle.TYPE_NONE; + BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); + if (vehicleActor != null) + ret = (int)vehicleActor.Type; + return ret; + } + set { + Vehicle type = (Vehicle)value; + + PhysScene.TaintedObject(LocalID, "setVehicleType", delegate() + { + // Some vehicle scripts change vehicle type on the fly as an easy way to + // change all the parameters. Like a plane changing to CAR when on the + // ground. In this case, don't want to zero motion. + // ZeroMotion(true /* inTaintTime */); + if (type == Vehicle.TYPE_NONE) + { + // Vehicle type is 'none' so get rid of any actor that may have been allocated. + BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */); + if (vehicleActor != null) + { + PhysicalActors.RemoveAndRelease(vehicleActor.ActorName); + } + } + else + { + // Vehicle type is not 'none' so create an actor and set it running. + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessTypeChange(type); + ActivateIfPhysical(false); + } + } + }); + } + } + public override void VehicleFloatParam(int param, float value) + { + PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate() + { + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value); ActivateIfPhysical(false); } }); } - else + public override void VehicleVectorParam(int param, OMV.Vector3 value) { - m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); + PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate() + { + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value); + ActivateIfPhysical(false); + } + }); + } + public override void VehicleRotationParam(int param, OMV.Quaternion rotation) + { + PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate() + { + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation); + ActivateIfPhysical(false); + } + }); + } + public override void VehicleFlags(int param, bool remove) + { + PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate() + { + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null) + { + vehicleActor.ProcessVehicleFlags(param, remove); + } + }); + } + + public override void SetVehicle(object pvdata) + { + PhysScene.TaintedObject(LocalID, "BSPrim.SetVehicle", delegate () + { + BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */); + if (vehicleActor != null && (pvdata is VehicleData) ) + { + VehicleData vdata = (VehicleData)pvdata; + // vehicleActor.ProcessSetVehicle((VehicleData)vdata); + + vehicleActor.ProcessTypeChange(vdata.m_type); + vehicleActor.ProcessVehicleFlags(-1, false); + vehicleActor.ProcessVehicleFlags((int)vdata.m_flags, false); + + // Linear properties + vehicleActor.ProcessVectorVehicleParam(Vehicle.LINEAR_MOTOR_DIRECTION, vdata.m_linearMotorDirection); + vehicleActor.ProcessVectorVehicleParam(Vehicle.LINEAR_FRICTION_TIMESCALE, vdata.m_linearFrictionTimescale); + vehicleActor.ProcessFloatVehicleParam(Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE, vdata.m_linearMotorDecayTimescale); + vehicleActor.ProcessFloatVehicleParam(Vehicle.LINEAR_MOTOR_TIMESCALE, vdata.m_linearMotorTimescale); + vehicleActor.ProcessVectorVehicleParam(Vehicle.LINEAR_MOTOR_OFFSET, vdata.m_linearMotorOffset); + + //Angular properties + vehicleActor.ProcessVectorVehicleParam(Vehicle.ANGULAR_MOTOR_DIRECTION, vdata.m_angularMotorDirection); + vehicleActor.ProcessFloatVehicleParam(Vehicle.ANGULAR_MOTOR_TIMESCALE, vdata.m_angularMotorTimescale); + vehicleActor.ProcessFloatVehicleParam(Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE, vdata.m_angularMotorDecayTimescale); + vehicleActor.ProcessVectorVehicleParam(Vehicle.ANGULAR_FRICTION_TIMESCALE, vdata.m_angularFrictionTimescale); + + //Deflection properties + vehicleActor.ProcessFloatVehicleParam(Vehicle.ANGULAR_DEFLECTION_EFFICIENCY, vdata.m_angularDeflectionEfficiency); + vehicleActor.ProcessFloatVehicleParam(Vehicle.ANGULAR_DEFLECTION_TIMESCALE, vdata.m_angularDeflectionTimescale); + vehicleActor.ProcessFloatVehicleParam(Vehicle.LINEAR_DEFLECTION_EFFICIENCY, vdata.m_linearDeflectionEfficiency); + vehicleActor.ProcessFloatVehicleParam(Vehicle.LINEAR_DEFLECTION_TIMESCALE, vdata.m_linearDeflectionTimescale); + + //Banking properties + vehicleActor.ProcessFloatVehicleParam(Vehicle.BANKING_EFFICIENCY, vdata.m_bankingEfficiency); + vehicleActor.ProcessFloatVehicleParam(Vehicle.BANKING_MIX, vdata.m_bankingMix); + vehicleActor.ProcessFloatVehicleParam(Vehicle.BANKING_TIMESCALE, vdata.m_bankingTimescale); + + //Hover and Buoyancy properties + vehicleActor.ProcessFloatVehicleParam(Vehicle.HOVER_HEIGHT, vdata.m_VhoverHeight); + vehicleActor.ProcessFloatVehicleParam(Vehicle.HOVER_EFFICIENCY, vdata.m_VhoverEfficiency); + vehicleActor.ProcessFloatVehicleParam(Vehicle.HOVER_TIMESCALE, vdata.m_VhoverTimescale); + vehicleActor.ProcessFloatVehicleParam(Vehicle.BUOYANCY, vdata.m_VehicleBuoyancy); + + //Attractor properties + vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, vdata.m_verticalAttractionEfficiency); + vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, vdata.m_verticalAttractionTimescale); + + vehicleActor.ProcessRotationVehicleParam(Vehicle.REFERENCE_FRAME, vdata.m_referenceFrame); + } + }); + } + + // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more + public override void SetVolumeDetect(int param) { + bool newValue = (param != 0); + if (_isVolumeDetect != newValue) + { + _isVolumeDetect = newValue; + PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate() + { + // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect); + SetObjectDynamic(true); + }); + } return; } - } + public override bool IsVolumeDetect + { + get { return _isVolumeDetect; } + } + public override void SetMaterial(int material) + { + base.SetMaterial(material); + PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate() + { + UpdatePhysicalParameters(); + }); + } + public override float Friction + { + get { return base.Friction; } + set + { + if (base.Friction != value) + { + base.Friction = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + } + public override float Restitution + { + get { return base.Restitution; } + set + { + if (base.Restitution != value) + { + base.Restitution = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + } + // The simulator/viewer keep density as 100kg/m3. + // Remember to use BSParam.DensityScaleFactor to create the physical density. + public override float Density + { + get { return base.Density; } + set + { + if (base.Density != value) + { + base.Density = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + } + public override float GravModifier + { + get { return base.GravModifier; } + set + { + if (base.GravModifier != value) + { + base.GravModifier = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + } + public override OMV.Vector3 ForceVelocity { + get { return RawVelocity; } + set { + RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity); + if (PhysBody.HasPhysicalBody) + { + DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity); + PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); + ActivateIfPhysical(false); + } + } + } + public override OMV.Vector3 Torque { + get { return RawTorque; } + set { + RawTorque = value; + EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate() + { + return new BSActorSetTorque(PhysScene, this, SetTorqueActorName); + }); + DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque); - // A torque impulse. - // ApplyTorqueImpulse adds torque directly to the angularVelocity. - // AddAngularForce accumulates the force and applied it to the angular velocity all at once. - // Computed as: angularVelocity += impulse * inertia; - public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) - { - OMV.Vector3 applyImpulse = impulse; - PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate() + // Call update so actor Refresh() is called to start things off + PhysScene.TaintedObject(LocalID, "BSPrim.setTorque", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + public override OMV.Vector3 Acceleration { + get { return _acceleration; } + set { _acceleration = value; } + } + + public override OMV.Quaternion Orientation { + get { + return RawOrientation; + } + set { + if (RawOrientation == value) + return; + RawOrientation = value; + + PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate() + { + ForceOrientation = RawOrientation; + }); + } + } + // Go directly to Bullet to get/set the value. + public override OMV.Quaternion ForceOrientation + { + get + { + RawOrientation = PhysScene.PE.GetOrientation(PhysBody); + return RawOrientation; + } + set + { + RawOrientation = value; + if (PhysBody.HasPhysicalBody) + PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); + } + } + public override int PhysicsActorType { + get { return _physicsActorType; } + set { _physicsActorType = value; } + } + public override bool IsPhysical { + get { return _isPhysical; } + set { + if (_isPhysical != value) + { + _isPhysical = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate() + { + DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); + SetObjectDynamic(true); + // whether phys-to-static or static-to-phys, the object is not moving. + ZeroMotion(true); + + }); + } + } + } + + // An object is static (does not move) if selected or not physical + public override bool IsStatic + { + get { return _isSelected || !IsPhysical; } + } + + // An object is solid if it's not phantom and if it's not doing VolumeDetect + public override bool IsSolid + { + get { return !IsPhantom && !_isVolumeDetect; } + } + + // The object is moving and is actively being dynamic in the physical world + public override bool IsPhysicallyActive + { + get { return !_isSelected && IsPhysical; } + } + + // Make gravity work if the object is physical and not selected + // Called at taint-time!! + private void SetObjectDynamic(bool forceRebuild) + { + // Recreate the physical object if necessary + CreateGeomAndObject(forceRebuild); + } + + // Convert the simulator's physical properties into settings on BulletSim objects. + // There are four flags we're interested in: + // IsStatic: Object does not move, otherwise the object has mass and moves + // isSolid: other objects bounce off of this object + // isVolumeDetect: other objects pass through but can generate collisions + // collisionEvents: whether this object returns collision events + // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters. + public virtual void UpdatePhysicalParameters() + { + if (!PhysBody.HasPhysicalBody) + { + // This would only happen if updates are called for during initialization when the body is not set up yet. + // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID); + return; + } + + // Mangling all the physical properties requires the object not be in the physical world. + // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). + PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); + + // Set up the object physicalness (does gravity and collisions move this object) + MakeDynamic(IsStatic); + + // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) + PhysicalActors.Refresh(); + + // Arrange for collision events if the simulator wants them + EnableCollisions(SubscribedEvents()); + + // Make solid or not (do things bounce off or pass through this object). + MakeSolid(IsSolid); + + AddObjectToPhysicalWorld(); + + // Rebuild its shape + PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); + + DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}", + LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), + CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape); + } + + // "Making dynamic" means changing to and from static. + // When static, gravity does not effect the object and it is fixed in space. + // When dynamic, the object can fall and be pushed by others. + // This is independent of its 'solidness' which controls what passes through + // this object and what interacts with it. + protected virtual void MakeDynamic(bool makeStatic) + { + if (makeStatic) + { + // Become a Bullet 'static' object type + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); + // Stop all movement + ZeroMotion(true); + + // Set various physical properties so other object interact properly + PhysScene.PE.SetFriction(PhysBody, Friction); + PhysScene.PE.SetRestitution(PhysBody, Restitution); + PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); + + // Mass is zero which disables a bunch of physics stuff in Bullet + UpdatePhysicalMassProperties(0f, false); + // Set collision detection parameters + if (BSParam.CcdMotionThreshold > 0f) + { + PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); + PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); + } + + // The activation state is 'disabled' so Bullet will not try to act on it. + // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION); + // Start it out sleeping and physical actions could wake it up. + PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING); + + // This collides like a static object + PhysBody.collisionType = CollisionType.Static; + } + else + { + // Not a Bullet static object + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT); + + // Set various physical properties so other object interact properly + PhysScene.PE.SetFriction(PhysBody, Friction); + PhysScene.PE.SetRestitution(PhysBody, Restitution); + // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution); + + // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 + // Since this can be called multiple times, only zero forces when becoming physical + // PhysicsScene.PE.ClearAllForces(BSBody); + + // For good measure, make sure the transform is set through to the motion state + ForcePosition = RawPosition; + ForceVelocity = RawVelocity; + ForceRotationalVelocity = RawRotationalVelocity; + + // A dynamic object has mass + UpdatePhysicalMassProperties(RawMass, false); + + // Set collision detection parameters + if (BSParam.CcdMotionThreshold > 0f) + { + PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); + PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); + } + + // Various values for simulation limits + PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping); + PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime); + PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold); + PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); + + // This collides like an object. + PhysBody.collisionType = CollisionType.Dynamic; + + // Force activation of the object so Bullet will act on it. + // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. + PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); + } + } + + // "Making solid" means that other object will not pass through this object. + // To make transparent, we create a Bullet ghost object. + // Note: This expects to be called from the UpdatePhysicalParameters() routine as + // the functions after this one set up the state of a possibly newly created collision body. + private void MakeSolid(bool makeSolid) + { + CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody); + if (makeSolid) + { + // Verify the previous code created the correct shape for this type of thing. + if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0) + { + m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); + } + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); + } + else + { + if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0) + { + m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); + } + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE); + + // Change collision info from a static object to a ghosty collision object + PhysBody.collisionType = CollisionType.VolumeDetect; + } + } + + // Turn on or off the flag controlling whether collision events are returned to the simulator. + private void EnableCollisions(bool wantsCollisionEvents) + { + if (wantsCollisionEvents) + { + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + } + else + { + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); + } + } + + // Add me to the physical world. + // Object MUST NOT already be in the world. + // This routine exists because some assorted properties get mangled by adding to the world. + internal void AddObjectToPhysicalWorld() { if (PhysBody.HasPhysicalBody) { - PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); + PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); + } + else + { + m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID); + DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType); + } + } + + // prims don't fly + public override bool Flying { + get { return _flying; } + set { + _flying = value; + } + } + public override bool SetAlwaysRun { + get { return _setAlwaysRun; } + set { _setAlwaysRun = value; } + } + public override bool ThrottleUpdates { + get { return _throttleUpdates; } + set { _throttleUpdates = value; } + } + public bool IsPhantom { + get { + // SceneObjectPart removes phantom objects from the physics scene + // so, although we could implement touching and such, we never + // are invoked as a phantom object + return false; + } + } + public override bool FloatOnWater { + set { + _floatOnWater = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate() + { + if (_floatOnWater) + CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); + else + CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); + }); + } + } + public override bool Kinematic { + get { return _kinematic; } + set { _kinematic = value; + // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic); + } + } + public override float Buoyancy { + get { return _buoyancy; } + set { + _buoyancy = value; + PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate() + { + ForceBuoyancy = _buoyancy; + }); + } + } + public override float ForceBuoyancy { + get { return _buoyancy; } + set { + _buoyancy = value; + // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); + // Force the recalculation of the various inertia,etc variables in the object + UpdatePhysicalMassProperties(RawMass, true); + DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity); ActivateIfPhysical(false); } - }); - } + } - #region Mass Calculation - - private float CalculateMass() - { - float volume = _size.X * _size.Y * _size.Z; // default - float tmp; - - float returnMass = 0; - float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f; - float hollowVolume = hollowAmount * hollowAmount; - - switch (BaseShape.ProfileShape) + public override bool PIDActive { - case ProfileShape.Square: - // default box + get + { + return MoveToTargetActive; + } - if (BaseShape.PathCurve == (byte)Extrusion.Straight) - { - if (hollowAmount > 0.0) - { - switch (BaseShape.HollowShape) - { - case HollowShape.Square: - case HollowShape.Same: - break; + set + { + MoveToTargetActive = value; - case HollowShape.Circle: - - hollowVolume *= 0.78539816339f; - break; - - case HollowShape.Triangle: - - hollowVolume *= (0.5f * .5f); - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - - else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) - { - //a tube - - volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX); - tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY); - volume -= volume*tmp*tmp; - - if (hollowAmount > 0.0) - { - hollowVolume *= hollowAmount; - - switch (BaseShape.HollowShape) - { - case HollowShape.Square: - case HollowShape.Same: - break; - - case HollowShape.Circle: - hollowVolume *= 0.78539816339f;; - break; - - case HollowShape.Triangle: - hollowVolume *= 0.5f * 0.5f; - break; - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - - break; - - case ProfileShape.Circle: - - if (BaseShape.PathCurve == (byte)Extrusion.Straight) - { - volume *= 0.78539816339f; // elipse base - - if (hollowAmount > 0.0) - { - switch (BaseShape.HollowShape) - { - case HollowShape.Same: - case HollowShape.Circle: - break; - - case HollowShape.Square: - hollowVolume *= 0.5f * 2.5984480504799f; - break; - - case HollowShape.Triangle: - hollowVolume *= .5f * 1.27323954473516f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - - else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) - { - volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX); - tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); - volume *= (1.0f - tmp * tmp); - - if (hollowAmount > 0.0) - { - - // calculate the hollow volume by it's shape compared to the prim shape - hollowVolume *= hollowAmount; - - switch (BaseShape.HollowShape) - { - case HollowShape.Same: - case HollowShape.Circle: - break; - - case HollowShape.Square: - hollowVolume *= 0.5f * 2.5984480504799f; - break; - - case HollowShape.Triangle: - hollowVolume *= .5f * 1.27323954473516f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); - } - } - break; - - case ProfileShape.HalfCircle: - if (BaseShape.PathCurve == (byte)Extrusion.Curve1) + EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate() { - volume *= 0.52359877559829887307710723054658f; + return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName); + }); + + // Call update so actor Refresh() is called to start things off + PhysScene.TaintedObject(LocalID, "BSPrim.PIDActive", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + + public override OMV.Vector3 PIDTarget + { + set + { + base.PIDTarget = value; + BSActor actor; + if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor)) + { + // if the actor exists, tell it to refresh its values. + actor.Refresh(); } - break; - case ProfileShape.EquilateralTriangle: + } + } + // Used for llSetHoverHeight and maybe vehicle height + // Hover Height will override MoveTo target's Z + public override bool PIDHoverActive { + get + { + return base.HoverActive; + } + set { + base.HoverActive = value; + EnableActor(HoverActive, HoverActorName, delegate() + { + return new BSActorHover(PhysScene, this, HoverActorName); + }); - if (BaseShape.PathCurve == (byte)Extrusion.Straight) + // Call update so actor Refresh() is called to start things off + PhysScene.TaintedObject(LocalID, "BSPrim.PIDHoverActive", delegate() + { + UpdatePhysicalParameters(); + }); + } + } + + public override void AddForce(OMV.Vector3 force, bool pushforce) { + // Per documentation, max force is limited. + OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); + + // Push forces seem to be scaled differently (follow pattern in ubODE) + if (!pushforce) { + // Since this force is being applied in only one step, make this a force per second. + addForce /= PhysScene.LastTimeStep; + } + + AddForce(false /* inTaintTime */, addForce); + } + + // Applying a force just adds this to the total force on the object. + // This added force will only last the next simulation tick. + public override void AddForce(bool inTaintTime, OMV.Vector3 force) { + // for an object, doesn't matter if force is a pushforce or not + if (IsPhysicallyActive) + { + if (force.IsFinite()) + { + // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce); + + OMV.Vector3 addForce = force; + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate() { - volume *= 0.32475953f; - - if (hollowAmount > 0.0) + // Bullet adds this central force to the total force for this tick. + // Deep down in Bullet: + // linearVelocity += totalForce / mass * timeStep; + DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce); + if (PhysBody.HasPhysicalBody) { - - // calculate the hollow volume by it's shape compared to the prim shape - switch (BaseShape.HollowShape) - { - case HollowShape.Same: - case HollowShape.Triangle: - hollowVolume *= .25f; - break; - - case HollowShape.Square: - hollowVolume *= 0.499849f * 3.07920140172638f; - break; - - case HollowShape.Circle: - // Hollow shape is a perfect cyllinder in respect to the cube's scale - // Cyllinder hollow volume calculation - - hollowVolume *= 0.1963495f * 3.07920140172638f; - break; - - default: - hollowVolume = 0; - break; - } - volume *= (1.0f - hollowVolume); + PhysScene.PE.ApplyCentralForce(PhysBody, addForce); + ActivateIfPhysical(false); } + }); + } + else + { + m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); + return; + } + } + } + + public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) { + // for an object, doesn't matter if force is a pushforce or not + if (!IsPhysicallyActive) + { + if (impulse.IsFinite()) + { + OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude); + // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse); + + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate() + { + // Bullet adds this impulse immediately to the velocity + DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse); + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse); + ActivateIfPhysical(false); + } + }); + } + else + { + m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID); + return; + } + } + } + + // BSPhysObject.AddAngularForce() + public override void AddAngularForce(bool inTaintTime, OMV.Vector3 force) + { + if (force.IsFinite()) + { + OMV.Vector3 angForce = force; + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate() + { + if (PhysBody.HasPhysicalBody) + { + DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce); + PhysScene.PE.ApplyTorque(PhysBody, angForce); + ActivateIfPhysical(false); } - else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) - { - volume *= 0.32475953f; - volume *= 0.01f * (float)(200 - BaseShape.PathScaleX); - tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); - volume *= (1.0f - tmp * tmp); + }); + } + else + { + m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); + return; + } + } - if (hollowAmount > 0.0) + // A torque impulse. + // ApplyTorqueImpulse adds torque directly to the angularVelocity. + // AddAngularForce accumulates the force and applied it to the angular velocity all at once. + // Computed as: angularVelocity += impulse * inertia; + public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) + { + OMV.Vector3 applyImpulse = impulse; + PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate() + { + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse); + ActivateIfPhysical(false); + } + }); + } + + #region Mass Calculation + + private float CalculateMass() + { + float volume = _size.X * _size.Y * _size.Z; // default + float tmp; + + float returnMass = 0; + float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f; + float hollowVolume = hollowAmount * hollowAmount; + + switch (BaseShape.ProfileShape) + { + case ProfileShape.Square: + // default box + + if (BaseShape.PathCurve == (byte)Extrusion.Straight) { - - hollowVolume *= hollowAmount; - - switch (BaseShape.HollowShape) + if (hollowAmount > 0.0) { - case HollowShape.Same: - case HollowShape.Triangle: - hollowVolume *= .25f; - break; + switch (BaseShape.HollowShape) + { + case HollowShape.Square: + case HollowShape.Same: + break; - case HollowShape.Square: - hollowVolume *= 0.499849f * 3.07920140172638f; - break; + case HollowShape.Circle: - case HollowShape.Circle: + hollowVolume *= 0.78539816339f; + break; - hollowVolume *= 0.1963495f * 3.07920140172638f; - break; + case HollowShape.Triangle: - default: - hollowVolume = 0; - break; + hollowVolume *= (0.5f * .5f); + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); } - volume *= (1.0f - hollowVolume); } + + else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) + { + //a tube + + volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX); + tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY); + volume -= volume*tmp*tmp; + + if (hollowAmount > 0.0) + { + hollowVolume *= hollowAmount; + + switch (BaseShape.HollowShape) + { + case HollowShape.Square: + case HollowShape.Same: + break; + + case HollowShape.Circle: + hollowVolume *= 0.78539816339f;; + break; + + case HollowShape.Triangle: + hollowVolume *= 0.5f * 0.5f; + break; + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + + break; + + case ProfileShape.Circle: + + if (BaseShape.PathCurve == (byte)Extrusion.Straight) + { + volume *= 0.78539816339f; // elipse base + + if (hollowAmount > 0.0) + { + switch (BaseShape.HollowShape) + { + case HollowShape.Same: + case HollowShape.Circle: + break; + + case HollowShape.Square: + hollowVolume *= 0.5f * 2.5984480504799f; + break; + + case HollowShape.Triangle: + hollowVolume *= .5f * 1.27323954473516f; + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + + else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) + { + volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX); + tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); + volume *= (1.0f - tmp * tmp); + + if (hollowAmount > 0.0) + { + + // calculate the hollow volume by it's shape compared to the prim shape + hollowVolume *= hollowAmount; + + switch (BaseShape.HollowShape) + { + case HollowShape.Same: + case HollowShape.Circle: + break; + + case HollowShape.Square: + hollowVolume *= 0.5f * 2.5984480504799f; + break; + + case HollowShape.Triangle: + hollowVolume *= .5f * 1.27323954473516f; + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + break; + + case ProfileShape.HalfCircle: + if (BaseShape.PathCurve == (byte)Extrusion.Curve1) + { + volume *= 0.52359877559829887307710723054658f; } break; - default: - break; - } + case ProfileShape.EquilateralTriangle: - - - float taperX1; - float taperY1; - float taperX; - float taperY; - float pathBegin; - float pathEnd; - float profileBegin; - float profileEnd; - - if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible) - { - taperX1 = BaseShape.PathScaleX * 0.01f; - if (taperX1 > 1.0f) - taperX1 = 2.0f - taperX1; - taperX = 1.0f - taperX1; - - taperY1 = BaseShape.PathScaleY * 0.01f; - if (taperY1 > 1.0f) - taperY1 = 2.0f - taperY1; - taperY = 1.0f - taperY1; - } - else - { - taperX = BaseShape.PathTaperX * 0.01f; - if (taperX < 0.0f) - taperX = -taperX; - taperX1 = 1.0f - taperX; - - taperY = BaseShape.PathTaperY * 0.01f; - if (taperY < 0.0f) - taperY = -taperY; - taperY1 = 1.0f - taperY; - - } - - - volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); - - pathBegin = (float)BaseShape.PathBegin * 2.0e-5f; - pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f; - volume *= (pathEnd - pathBegin); - - // this is crude aproximation - profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f; - profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; - volume *= (profileEnd - profileBegin); - - returnMass = Density * BSParam.DensityScaleFactor * volume; - - returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); - // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); - DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}", - LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size); - - return returnMass; - }// end CalculateMass - #endregion Mass Calculation - - // Rebuild the geometry and object. - // This is called when the shape changes so we need to recreate the mesh/hull. - // Called at taint-time!!! - public void CreateGeomAndObject(bool forceRebuild) - { - // Create the correct physical representation for this type of object. - // Updates base.PhysBody and base.PhysShape with the new information. - // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. - PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape) - { - // Called if the current prim body is about to be destroyed. - // Remove all the physical dependencies on the old body. - // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) - // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints. - RemoveDependencies(); - }); - - // Make sure the properties are set on the new object - UpdatePhysicalParameters(); - return; - } - - // Called at taint-time - protected virtual void RemoveDependencies() - { - PhysicalActors.RemoveDependencies(); - } - - #region Extension - public override object Extension(string pFunct, params object[] pParams) - { - DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct); - object ret = null; - switch (pFunct) - { - case ExtendedPhysics.PhysFunctAxisLockLimits: - ret = SetAxisLockLimitsExtension(pParams); - break; - default: - ret = base.Extension(pFunct, pParams); - break; - } - return ret; - } - - private void InitializeAxisActor() - { - EnableActor(LockedAngularAxis != LockedAxisFree || LockedLinearAxis != LockedAxisFree, - LockedAxisActorName, delegate() - { - return new BSActorLockAxis(PhysScene, this, LockedAxisActorName); - }); - - // Update parameters so the new actor's Refresh() action is called at the right time. - PhysScene.TaintedObject(LocalID, "BSPrim.LockAxis", delegate() - { - UpdatePhysicalParameters(); - }); - } - - // Passed an array of an array of parameters, set the axis locking. - // This expects an int (PHYS_AXIS_*) followed by none or two limit floats - // followed by another int and floats, etc. - private object SetAxisLockLimitsExtension(object[] pParams) - { - DetailLog("{0} SetAxisLockLimitsExtension. parmlen={1}", LocalID, pParams.GetLength(0)); - object ret = null; - try - { - if (pParams.GetLength(0) > 1) - { - int index = 2; - while (index < pParams.GetLength(0)) - { - var funct = pParams[index]; - DetailLog("{0} SetAxisLockLimitsExtension. op={1}, index={2}", LocalID, funct, index); - if (funct is Int32 || funct is Int64) - { - switch ((int)funct) + if (BaseShape.PathCurve == (byte)Extrusion.Straight) { - // Those that take no parameters - case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR: - case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X: - case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y: - case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z: - case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR: - case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X: - case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y: - case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z: - case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR: - case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X: - case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y: - case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z: - case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR: - case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X: - case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y: - case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z: - case ExtendedPhysics.PHYS_AXIS_UNLOCK: - ApplyAxisLimits((int)funct, 0f, 0f); - index += 1; - break; - // Those that take two parameters (the limits) - case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X: - case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y: - case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z: - case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X: - case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y: - case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z: - ApplyAxisLimits((int)funct, (float)pParams[index + 1], (float)pParams[index + 2]); - index += 3; - break; - default: - m_log.WarnFormat("{0} SetSxisLockLimitsExtension. Unknown op={1}", LogHeader, funct); - index += 1; - break; + volume *= 0.32475953f; + + if (hollowAmount > 0.0) + { + + // calculate the hollow volume by it's shape compared to the prim shape + switch (BaseShape.HollowShape) + { + case HollowShape.Same: + case HollowShape.Triangle: + hollowVolume *= .25f; + break; + + case HollowShape.Square: + hollowVolume *= 0.499849f * 3.07920140172638f; + break; + + case HollowShape.Circle: + // Hollow shape is a perfect cyllinder in respect to the cube's scale + // Cyllinder hollow volume calculation + + hollowVolume *= 0.1963495f * 3.07920140172638f; + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + else if (BaseShape.PathCurve == (byte)Extrusion.Curve1) + { + volume *= 0.32475953f; + volume *= 0.01f * (float)(200 - BaseShape.PathScaleX); + tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY); + volume *= (1.0f - tmp * tmp); + + if (hollowAmount > 0.0) + { + + hollowVolume *= hollowAmount; + + switch (BaseShape.HollowShape) + { + case HollowShape.Same: + case HollowShape.Triangle: + hollowVolume *= .25f; + break; + + case HollowShape.Square: + hollowVolume *= 0.499849f * 3.07920140172638f; + break; + + case HollowShape.Circle: + + hollowVolume *= 0.1963495f * 3.07920140172638f; + break; + + default: + hollowVolume = 0; + break; + } + volume *= (1.0f - hollowVolume); + } + } + break; + + default: + break; + } + + + + float taperX1; + float taperY1; + float taperX; + float taperY; + float pathBegin; + float pathEnd; + float profileBegin; + float profileEnd; + + if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible) + { + taperX1 = BaseShape.PathScaleX * 0.01f; + if (taperX1 > 1.0f) + taperX1 = 2.0f - taperX1; + taperX = 1.0f - taperX1; + + taperY1 = BaseShape.PathScaleY * 0.01f; + if (taperY1 > 1.0f) + taperY1 = 2.0f - taperY1; + taperY = 1.0f - taperY1; + } + else + { + taperX = BaseShape.PathTaperX * 0.01f; + if (taperX < 0.0f) + taperX = -taperX; + taperX1 = 1.0f - taperX; + + taperY = BaseShape.PathTaperY * 0.01f; + if (taperY < 0.0f) + taperY = -taperY; + taperY1 = 1.0f - taperY; + + } + + + volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY); + + pathBegin = (float)BaseShape.PathBegin * 2.0e-5f; + pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f; + volume *= (pathEnd - pathBegin); + + // this is crude aproximation + profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f; + profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f; + volume *= (profileEnd - profileBegin); + + returnMass = Density * BSParam.DensityScaleFactor * volume; + + returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass); + // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass); + DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}", + LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size); + + return returnMass; + }// end CalculateMass + #endregion Mass Calculation + + // Rebuild the geometry and object. + // This is called when the shape changes so we need to recreate the mesh/hull. + // Called at taint-time!!! + public void CreateGeomAndObject(bool forceRebuild) + { + // Create the correct physical representation for this type of object. + // Updates base.PhysBody and base.PhysShape with the new information. + // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary. + PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape) + { + // Called if the current prim body is about to be destroyed. + // Remove all the physical dependencies on the old body. + // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) + // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints. + RemoveDependencies(); + }); + + // Make sure the properties are set on the new object + UpdatePhysicalParameters(); + return; + } + + // Called at taint-time + protected virtual void RemoveDependencies() + { + PhysicalActors.RemoveDependencies(); + } + + #region Extension + public override object Extension(string pFunct, params object[] pParams) + { + DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct); + object ret = null; + switch (pFunct) + { + case ExtendedPhysics.PhysFunctAxisLockLimits: + ret = SetAxisLockLimitsExtension(pParams); + break; + default: + ret = base.Extension(pFunct, pParams); + break; + } + return ret; + } + + private void InitializeAxisActor() + { + EnableActor(LockedAngularAxis != LockedAxisFree || LockedLinearAxis != LockedAxisFree, + LockedAxisActorName, delegate() + { + return new BSActorLockAxis(PhysScene, this, LockedAxisActorName); + }); + + // Update parameters so the new actor's Refresh() action is called at the right time. + PhysScene.TaintedObject(LocalID, "BSPrim.LockAxis", delegate() + { + UpdatePhysicalParameters(); + }); + } + + // Passed an array of an array of parameters, set the axis locking. + // This expects an int (PHYS_AXIS_*) followed by none or two limit floats + // followed by another int and floats, etc. + private object SetAxisLockLimitsExtension(object[] pParams) + { + DetailLog("{0} SetAxisLockLimitsExtension. parmlen={1}", LocalID, pParams.GetLength(0)); + object ret = null; + try + { + if (pParams.GetLength(0) > 1) + { + int index = 2; + while (index < pParams.GetLength(0)) + { + var funct = pParams[index]; + DetailLog("{0} SetAxisLockLimitsExtension. op={1}, index={2}", LocalID, funct, index); + if (funct is Int32 || funct is Int64) + { + switch ((int)funct) + { + // Those that take no parameters + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR: + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X: + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y: + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z: + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR: + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X: + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y: + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y: + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z: + case ExtendedPhysics.PHYS_AXIS_UNLOCK: + ApplyAxisLimits((int)funct, 0f, 0f); + index += 1; + break; + // Those that take two parameters (the limits) + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X: + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y: + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z: + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X: + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y: + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z: + ApplyAxisLimits((int)funct, (float)pParams[index + 1], (float)pParams[index + 2]); + index += 3; + break; + default: + m_log.WarnFormat("{0} SetSxisLockLimitsExtension. Unknown op={1}", LogHeader, funct); + index += 1; + break; + } } } + InitializeAxisActor(); + ret = (object)index; } - InitializeAxisActor(); - ret = (object)index; } + catch (Exception e) + { + m_log.WarnFormat("{0} SetSxisLockLimitsExtension exception in object {1}: {2}", LogHeader, this.Name, e); + ret = null; + } + return ret; // not implemented yet } - catch (Exception e) + + // Set the locking parameters. + // If an axis is locked, the limits for the axis are set to zero, + // If the axis is being constrained, the high and low value are passed and set. + // When done here, LockedXXXAxis flags are set and LockedXXXAxixLow/High are set to the range. + protected void ApplyAxisLimits(int funct, float low, float high) { - m_log.WarnFormat("{0} SetSxisLockLimitsExtension exception in object {1}: {2}", LogHeader, this.Name, e); - ret = null; + DetailLog("{0} ApplyAxisLimits. op={1}, low={2}, high={3}", LocalID, funct, low, high); + float linearMax = 23000f; + float angularMax = (float)Math.PI; + + switch (funct) + { + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR: + this.LockedLinearAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis); + this.LockedLinearAxisLow = OMV.Vector3.Zero; + this.LockedLinearAxisHigh = OMV.Vector3.Zero; + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X: + this.LockedLinearAxis.X = LockedAxis; + this.LockedLinearAxisLow.X = 0f; + this.LockedLinearAxisHigh.X = 0f; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X: + this.LockedLinearAxis.X = LockedAxis; + this.LockedLinearAxisLow.X = Util.Clip(low, -linearMax, linearMax); + this.LockedLinearAxisHigh.X = Util.Clip(high, -linearMax, linearMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y: + this.LockedLinearAxis.Y = LockedAxis; + this.LockedLinearAxisLow.Y = 0f; + this.LockedLinearAxisHigh.Y = 0f; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y: + this.LockedLinearAxis.Y = LockedAxis; + this.LockedLinearAxisLow.Y = Util.Clip(low, -linearMax, linearMax); + this.LockedLinearAxisHigh.Y = Util.Clip(high, -linearMax, linearMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z: + this.LockedLinearAxis.Z = LockedAxis; + this.LockedLinearAxisLow.Z = 0f; + this.LockedLinearAxisHigh.Z = 0f; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z: + this.LockedLinearAxis.Z = LockedAxis; + this.LockedLinearAxisLow.Z = Util.Clip(low, -linearMax, linearMax); + this.LockedLinearAxisHigh.Z = Util.Clip(high, -linearMax, linearMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR: + this.LockedAngularAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis); + this.LockedAngularAxisLow = OMV.Vector3.Zero; + this.LockedAngularAxisHigh = OMV.Vector3.Zero; + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X: + this.LockedAngularAxis.X = LockedAxis; + this.LockedAngularAxisLow.X = 0; + this.LockedAngularAxisHigh.X = 0; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X: + this.LockedAngularAxis.X = LockedAxis; + this.LockedAngularAxisLow.X = Util.Clip(low, -angularMax, angularMax); + this.LockedAngularAxisHigh.X = Util.Clip(high, -angularMax, angularMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y: + this.LockedAngularAxis.Y = LockedAxis; + this.LockedAngularAxisLow.Y = 0; + this.LockedAngularAxisHigh.Y = 0; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y: + this.LockedAngularAxis.Y = LockedAxis; + this.LockedAngularAxisLow.Y = Util.Clip(low, -angularMax, angularMax); + this.LockedAngularAxisHigh.Y = Util.Clip(high, -angularMax, angularMax); + break; + case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z: + this.LockedAngularAxis.Z = LockedAxis; + this.LockedAngularAxisLow.Z = 0; + this.LockedAngularAxisHigh.Z = 0; + break; + case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z: + this.LockedAngularAxis.Z = LockedAxis; + this.LockedAngularAxisLow.Z = Util.Clip(low, -angularMax, angularMax); + this.LockedAngularAxisHigh.Z = Util.Clip(high, -angularMax, angularMax); + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR: + this.LockedLinearAxis = LockedAxisFree; + this.LockedLinearAxisLow = new OMV.Vector3(-linearMax, -linearMax, -linearMax); + this.LockedLinearAxisHigh = new OMV.Vector3(linearMax, linearMax, linearMax); + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X: + this.LockedLinearAxis.X = FreeAxis; + this.LockedLinearAxisLow.X = -linearMax; + this.LockedLinearAxisHigh.X = linearMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y: + this.LockedLinearAxis.Y = FreeAxis; + this.LockedLinearAxisLow.Y = -linearMax; + this.LockedLinearAxisHigh.Y = linearMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z: + this.LockedLinearAxis.Z = FreeAxis; + this.LockedLinearAxisLow.Z = -linearMax; + this.LockedLinearAxisHigh.Z = linearMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR: + this.LockedAngularAxis = LockedAxisFree; + this.LockedAngularAxisLow = new OMV.Vector3(-angularMax, -angularMax, -angularMax); + this.LockedAngularAxisHigh = new OMV.Vector3(angularMax, angularMax, angularMax); + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X: + this.LockedAngularAxis.X = FreeAxis; + this.LockedAngularAxisLow.X = -angularMax; + this.LockedAngularAxisHigh.X = angularMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y: + this.LockedAngularAxis.Y = FreeAxis; + this.LockedAngularAxisLow.Y = -angularMax; + this.LockedAngularAxisHigh.Y = angularMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z: + this.LockedAngularAxis.Z = FreeAxis; + this.LockedAngularAxisLow.Z = -angularMax; + this.LockedAngularAxisHigh.Z = angularMax; + break; + case ExtendedPhysics.PHYS_AXIS_UNLOCK: + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR, 0f, 0f); + ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f); + break; + default: + break; + } + return; } - return ret; // not implemented yet - } + #endregion // Extension - // Set the locking parameters. - // If an axis is locked, the limits for the axis are set to zero, - // If the axis is being constrained, the high and low value are passed and set. - // When done here, LockedXXXAxis flags are set and LockedXXXAxixLow/High are set to the range. - protected void ApplyAxisLimits(int funct, float low, float high) - { - DetailLog("{0} ApplyAxisLimits. op={1}, low={2}, high={3}", LocalID, funct, low, high); - float linearMax = 23000f; - float angularMax = (float)Math.PI; - - switch (funct) + // The physics engine says that properties have updated. Update same and inform + // the world that things have changed. + // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims. + // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position. + public override void UpdateProperties(EntityProperties entprop) { - case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR: - this.LockedLinearAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis); - this.LockedLinearAxisLow = OMV.Vector3.Zero; - this.LockedLinearAxisHigh = OMV.Vector3.Zero; - break; - case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X: - this.LockedLinearAxis.X = LockedAxis; - this.LockedLinearAxisLow.X = 0f; - this.LockedLinearAxisHigh.X = 0f; - break; - case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X: - this.LockedLinearAxis.X = LockedAxis; - this.LockedLinearAxisLow.X = Util.Clip(low, -linearMax, linearMax); - this.LockedLinearAxisHigh.X = Util.Clip(high, -linearMax, linearMax); - break; - case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y: - this.LockedLinearAxis.Y = LockedAxis; - this.LockedLinearAxisLow.Y = 0f; - this.LockedLinearAxisHigh.Y = 0f; - break; - case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y: - this.LockedLinearAxis.Y = LockedAxis; - this.LockedLinearAxisLow.Y = Util.Clip(low, -linearMax, linearMax); - this.LockedLinearAxisHigh.Y = Util.Clip(high, -linearMax, linearMax); - break; - case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z: - this.LockedLinearAxis.Z = LockedAxis; - this.LockedLinearAxisLow.Z = 0f; - this.LockedLinearAxisHigh.Z = 0f; - break; - case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z: - this.LockedLinearAxis.Z = LockedAxis; - this.LockedLinearAxisLow.Z = Util.Clip(low, -linearMax, linearMax); - this.LockedLinearAxisHigh.Z = Util.Clip(high, -linearMax, linearMax); - break; - case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR: - this.LockedAngularAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis); - this.LockedAngularAxisLow = OMV.Vector3.Zero; - this.LockedAngularAxisHigh = OMV.Vector3.Zero; - break; - case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X: - this.LockedAngularAxis.X = LockedAxis; - this.LockedAngularAxisLow.X = 0; - this.LockedAngularAxisHigh.X = 0; - break; - case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X: - this.LockedAngularAxis.X = LockedAxis; - this.LockedAngularAxisLow.X = Util.Clip(low, -angularMax, angularMax); - this.LockedAngularAxisHigh.X = Util.Clip(high, -angularMax, angularMax); - break; - case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y: - this.LockedAngularAxis.Y = LockedAxis; - this.LockedAngularAxisLow.Y = 0; - this.LockedAngularAxisHigh.Y = 0; - break; - case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y: - this.LockedAngularAxis.Y = LockedAxis; - this.LockedAngularAxisLow.Y = Util.Clip(low, -angularMax, angularMax); - this.LockedAngularAxisHigh.Y = Util.Clip(high, -angularMax, angularMax); - break; - case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z: - this.LockedAngularAxis.Z = LockedAxis; - this.LockedAngularAxisLow.Z = 0; - this.LockedAngularAxisHigh.Z = 0; - break; - case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z: - this.LockedAngularAxis.Z = LockedAxis; - this.LockedAngularAxisLow.Z = Util.Clip(low, -angularMax, angularMax); - this.LockedAngularAxisHigh.Z = Util.Clip(high, -angularMax, angularMax); - break; - case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR: - this.LockedLinearAxis = LockedAxisFree; - this.LockedLinearAxisLow = new OMV.Vector3(-linearMax, -linearMax, -linearMax); - this.LockedLinearAxisHigh = new OMV.Vector3(linearMax, linearMax, linearMax); - break; - case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X: - this.LockedLinearAxis.X = FreeAxis; - this.LockedLinearAxisLow.X = -linearMax; - this.LockedLinearAxisHigh.X = linearMax; - break; - case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y: - this.LockedLinearAxis.Y = FreeAxis; - this.LockedLinearAxisLow.Y = -linearMax; - this.LockedLinearAxisHigh.Y = linearMax; - break; - case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z: - this.LockedLinearAxis.Z = FreeAxis; - this.LockedLinearAxisLow.Z = -linearMax; - this.LockedLinearAxisHigh.Z = linearMax; - break; - case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR: - this.LockedAngularAxis = LockedAxisFree; - this.LockedAngularAxisLow = new OMV.Vector3(-angularMax, -angularMax, -angularMax); - this.LockedAngularAxisHigh = new OMV.Vector3(angularMax, angularMax, angularMax); - break; - case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X: - this.LockedAngularAxis.X = FreeAxis; - this.LockedAngularAxisLow.X = -angularMax; - this.LockedAngularAxisHigh.X = angularMax; - break; - case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y: - this.LockedAngularAxis.Y = FreeAxis; - this.LockedAngularAxisLow.Y = -angularMax; - this.LockedAngularAxisHigh.Y = angularMax; - break; - case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z: - this.LockedAngularAxis.Z = FreeAxis; - this.LockedAngularAxisLow.Z = -angularMax; - this.LockedAngularAxisHigh.Z = angularMax; - break; - case ExtendedPhysics.PHYS_AXIS_UNLOCK: - ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR, 0f, 0f); - ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f); - break; - default: - break; + // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. + TriggerPreUpdatePropertyAction(ref entprop); + + // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG + + // Assign directly to the local variables so the normal set actions do not happen + RawPosition = entprop.Position; + RawOrientation = entprop.Rotation; + // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be + // very sensitive to velocity changes. + if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold)) + RawVelocity = entprop.Velocity; + _acceleration = entprop.Acceleration; + RawRotationalVelocity = entprop.RotationalVelocity; + + // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG + + // The sanity check can change the velocity and/or position. + if (PositionSanityCheck(true /* inTaintTime */ )) + { + entprop.Position = RawPosition; + entprop.Velocity = RawVelocity; + entprop.RotationalVelocity = RawRotationalVelocity; + entprop.Acceleration = _acceleration; + } + + OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG + DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction); + + // remember the current and last set values + LastEntityProperties = CurrentEntityProperties; + CurrentEntityProperties = entprop; + + PhysScene.PostUpdate(this); } - return; - } - #endregion // Extension - - // The physics engine says that properties have updated. Update same and inform - // the world that things have changed. - // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims. - // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position. - public override void UpdateProperties(EntityProperties entprop) - { - // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. - TriggerPreUpdatePropertyAction(ref entprop); - - // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG - - // Assign directly to the local variables so the normal set actions do not happen - RawPosition = entprop.Position; - RawOrientation = entprop.Rotation; - // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be - // very sensitive to velocity changes. - if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold)) - RawVelocity = entprop.Velocity; - _acceleration = entprop.Acceleration; - RawRotationalVelocity = entprop.RotationalVelocity; - - // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG - - // The sanity check can change the velocity and/or position. - if (PositionSanityCheck(true /* inTaintTime */ )) - { - entprop.Position = RawPosition; - entprop.Velocity = RawVelocity; - entprop.RotationalVelocity = RawRotationalVelocity; - entprop.Acceleration = _acceleration; - } - - OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG - DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction); - - // remember the current and last set values - LastEntityProperties = CurrentEntityProperties; - CurrentEntityProperties = entprop; - - PhysScene.PostUpdate(this); } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs index 3f90fc55b2..be37e83d77 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimDisplaced.cs @@ -37,145 +37,145 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -public class BSPrimDisplaced : BSPrim -{ - // The purpose of this subclass is to do any mapping between what the simulator thinks - // the prim position and orientation is and what the physical position/orientation. - // This difference happens because Bullet assumes the center-of-mass is the <0,0,0> - // of the prim/linkset. The simulator, on the other hand, tracks the location of - // the prim/linkset by the location of the root prim. So, if center-of-mass is anywhere - // but the origin of the root prim, the physical origin is displaced from the simulator origin. - // - // This routine works by capturing ForcePosition and - // adjusting the simulator values (being set) into the physical values. - // The conversion is also done in the opposite direction (physical origin -> simulator origin). - // - // The updateParameter call is also captured and the values from the physics engine - // are converted into simulator origin values before being passed to the base - // class. - - // PositionDisplacement is the vehicle relative distance from the root prim position to the center-of-mass. - public virtual OMV.Vector3 PositionDisplacement { get; set; } - - public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, - OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) - : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) + public class BSPrimDisplaced : BSPrim { - ClearDisplacement(); - } + // The purpose of this subclass is to do any mapping between what the simulator thinks + // the prim position and orientation is and what the physical position/orientation. + // This difference happens because Bullet assumes the center-of-mass is the <0,0,0> + // of the prim/linkset. The simulator, on the other hand, tracks the location of + // the prim/linkset by the location of the root prim. So, if center-of-mass is anywhere + // but the origin of the root prim, the physical origin is displaced from the simulator origin. + // + // This routine works by capturing ForcePosition and + // adjusting the simulator values (being set) into the physical values. + // The conversion is also done in the opposite direction (physical origin -> simulator origin). + // + // The updateParameter call is also captured and the values from the physics engine + // are converted into simulator origin values before being passed to the base + // class. - // Clears any center-of-mass displacement introduced by linksets, etc. - // Does not clear the displacement set by the user. - public void ClearDisplacement() - { - if (UserSetCenterOfMassDisplacement.HasValue) - PositionDisplacement = (OMV.Vector3)UserSetCenterOfMassDisplacement; - else - PositionDisplacement = OMV.Vector3.Zero; - } + // PositionDisplacement is the vehicle relative distance from the root prim position to the center-of-mass. + public virtual OMV.Vector3 PositionDisplacement { get; set; } - // Set this sets and computes the displacement from the passed prim to the center-of-mass. - // A user set value for center-of-mass overrides whatever might be passed in here. - // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). - // Returns the relative offset from the root position to the center-of-mass. - // Called at taint time. - public virtual Vector3 SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement) - { - Vector3 comDisp; - if (UserSetCenterOfMassDisplacement.HasValue) - comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement; - else - comDisp = centerOfMassDisplacement; - - // Eliminate any jitter caused be very slight differences in masses and positions - if (comDisp.ApproxEquals(Vector3.Zero, 0.01f) ) - comDisp = Vector3.Zero; - - DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}", - LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp); - if ( !comDisp.ApproxEquals(PositionDisplacement, 0.01f) ) + public BSPrimDisplaced(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, + OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) + : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) { - // Displacement setting is changing. - // The relationship between the physical object and simulated object must be aligned. - PositionDisplacement = comDisp; - this.ForcePosition = RawPosition; + ClearDisplacement(); } - return PositionDisplacement; - } + // Clears any center-of-mass displacement introduced by linksets, etc. + // Does not clear the displacement set by the user. + public void ClearDisplacement() + { + if (UserSetCenterOfMassDisplacement.HasValue) + PositionDisplacement = (OMV.Vector3)UserSetCenterOfMassDisplacement; + else + PositionDisplacement = OMV.Vector3.Zero; + } - // 'ForcePosition' is the one way to set the physical position of the body in the physics engine. - // Displace the simulator idea of position (center of root prim) to the physical position. - public override Vector3 ForcePosition - { - get { - OMV.Vector3 physPosition = PhysScene.PE.GetPosition(PhysBody); - if (PositionDisplacement != OMV.Vector3.Zero) + // Set this sets and computes the displacement from the passed prim to the center-of-mass. + // A user set value for center-of-mass overrides whatever might be passed in here. + // The displacement is in local coordinates (relative to root prim in linkset oriented coordinates). + // Returns the relative offset from the root position to the center-of-mass. + // Called at taint time. + public virtual Vector3 SetEffectiveCenterOfMassDisplacement(Vector3 centerOfMassDisplacement) + { + Vector3 comDisp; + if (UserSetCenterOfMassDisplacement.HasValue) + comDisp = (OMV.Vector3)UserSetCenterOfMassDisplacement; + else + comDisp = centerOfMassDisplacement; + + // Eliminate any jitter caused be very slight differences in masses and positions + if (comDisp.ApproxEquals(Vector3.Zero, 0.01f) ) + comDisp = Vector3.Zero; + + DetailLog("{0},BSPrimDisplaced.SetEffectiveCenterOfMassDisplacement,userSet={1},comDisp={2}", + LocalID, UserSetCenterOfMassDisplacement.HasValue, comDisp); + if ( !comDisp.ApproxEquals(PositionDisplacement, 0.01f) ) { - // If there is some displacement, return the physical position (center-of-mass) - // location minus the displacement to give the center of the root prim. - OMV.Vector3 displacement = PositionDisplacement * ForceOrientation; - DetailLog("{0},BSPrimDisplaced.ForcePosition,get,physPos={1},disp={2},simPos={3}", - LocalID, physPosition, displacement, physPosition - displacement); - physPosition -= displacement; + // Displacement setting is changing. + // The relationship between the physical object and simulated object must be aligned. + PositionDisplacement = comDisp; + this.ForcePosition = RawPosition; } - RawPosition = physPosition; - return physPosition; - } - set - { - if (PositionDisplacement != OMV.Vector3.Zero) - { - // This value is the simulator's idea of where the prim is: the center of the root prim - RawPosition = value; - // Move the passed root prim postion to the center-of-mass position and set in the physics engine. - OMV.Vector3 displacement = PositionDisplacement * RawOrientation; - OMV.Vector3 displacedPos = RawPosition + displacement; - DetailLog("{0},BSPrimDisplaced.ForcePosition,set,simPos={1},disp={2},physPos={3}", - LocalID, RawPosition, displacement, displacedPos); - if (PhysBody.HasPhysicalBody) + return PositionDisplacement; + } + + // 'ForcePosition' is the one way to set the physical position of the body in the physics engine. + // Displace the simulator idea of position (center of root prim) to the physical position. + public override Vector3 ForcePosition + { + get { + OMV.Vector3 physPosition = PhysScene.PE.GetPosition(PhysBody); + if (PositionDisplacement != OMV.Vector3.Zero) { - PhysScene.PE.SetTranslation(PhysBody, displacedPos, RawOrientation); - ActivateIfPhysical(false); + // If there is some displacement, return the physical position (center-of-mass) + // location minus the displacement to give the center of the root prim. + OMV.Vector3 displacement = PositionDisplacement * ForceOrientation; + DetailLog("{0},BSPrimDisplaced.ForcePosition,get,physPos={1},disp={2},simPos={3}", + LocalID, physPosition, displacement, physPosition - displacement); + physPosition -= displacement; + } + RawPosition = physPosition; + return physPosition; + } + set + { + if (PositionDisplacement != OMV.Vector3.Zero) + { + // This value is the simulator's idea of where the prim is: the center of the root prim + RawPosition = value; + + // Move the passed root prim postion to the center-of-mass position and set in the physics engine. + OMV.Vector3 displacement = PositionDisplacement * RawOrientation; + OMV.Vector3 displacedPos = RawPosition + displacement; + DetailLog("{0},BSPrimDisplaced.ForcePosition,set,simPos={1},disp={2},physPos={3}", + LocalID, RawPosition, displacement, displacedPos); + if (PhysBody.HasPhysicalBody) + { + PhysScene.PE.SetTranslation(PhysBody, displacedPos, RawOrientation); + ActivateIfPhysical(false); + } + } + else + { + base.ForcePosition = value; } } - else - { - base.ForcePosition = value; - } } - } - // These are also overridden by BSPrimLinkable if the prim can be part of a linkset - public override OMV.Vector3 CenterOfMass - { - get { return RawPosition; } - } - - public override OMV.Vector3 GeometricCenter - { - get { return RawPosition; } - } - - public override void UpdateProperties(EntityProperties entprop) - { - // Undo any center-of-mass displacement that might have been done. - if (PositionDisplacement != OMV.Vector3.Zero) + // These are also overridden by BSPrimLinkable if the prim can be part of a linkset + public override OMV.Vector3 CenterOfMass { - // The origional shape was offset from 'zero' by PositionDisplacement. - // These physical location must be back converted to be centered around the displaced - // root shape. - - // Move the returned center-of-mass location to the root prim location. - OMV.Vector3 displacement = PositionDisplacement * entprop.Rotation; - OMV.Vector3 displacedPos = entprop.Position - displacement; - DetailLog("{0},BSPrimDisplaced.UpdateProperties,physPos={1},disp={2},simPos={3}", - LocalID, entprop.Position, displacement, displacedPos); - entprop.Position = displacedPos; + get { return RawPosition; } } - base.UpdateProperties(entprop); + public override OMV.Vector3 GeometricCenter + { + get { return RawPosition; } + } + + public override void UpdateProperties(EntityProperties entprop) + { + // Undo any center-of-mass displacement that might have been done. + if (PositionDisplacement != OMV.Vector3.Zero) + { + // The origional shape was offset from 'zero' by PositionDisplacement. + // These physical location must be back converted to be centered around the displaced + // root shape. + + // Move the returned center-of-mass location to the root prim location. + OMV.Vector3 displacement = PositionDisplacement * entprop.Rotation; + OMV.Vector3 displacedPos = entprop.Position - displacement; + DetailLog("{0},BSPrimDisplaced.UpdateProperties,physPos={1},disp={2},simPos={3}", + LocalID, entprop.Position, displacement, displacedPos); + entprop.Position = displacedPos; + } + + base.UpdateProperties(entprop); + } } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs index 0d4be17ca0..bf1fa33c40 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrimLinkable.cs @@ -35,315 +35,315 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -public class BSPrimLinkable : BSPrimDisplaced -{ - // The purpose of this subclass is to add linkset functionality to the prim. This overrides - // operations necessary for keeping the linkset created and, additionally, this - // calls the linkset implementation for its creation and management. + public class BSPrimLinkable : BSPrimDisplaced + { + // The purpose of this subclass is to add linkset functionality to the prim. This overrides + // operations necessary for keeping the linkset created and, additionally, this + // calls the linkset implementation for its creation and management. #pragma warning disable 414 - private static readonly string LogHeader = "[BULLETS PRIMLINKABLE]"; + private static readonly string LogHeader = "[BULLETS PRIMLINKABLE]"; #pragma warning restore 414 - // This adds the overrides for link() and delink() so the prim is linkable. - - public BSLinkset Linkset { get; set; } - // The index of this child prim. - public int LinksetChildIndex { get; set; } - - public BSLinkset.LinksetImplementation LinksetType { get; set; } - - public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, - OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) - : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) - { - // Default linkset implementation for this prim - LinksetType = (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation; - - Linkset = BSLinkset.Factory(PhysScene, this); - - Linkset.Refresh(this); - } - - public override void Destroy() - { - Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime */); - base.Destroy(); - } - - public override void link(OpenSim.Region.PhysicsModules.SharedBase.PhysicsActor obj) - { - BSPrimLinkable parent = obj as BSPrimLinkable; - if (parent != null) + // This adds the overrides for link() and delink() so the prim is linkable. + + public BSLinkset Linkset { get; set; } + // The index of this child prim. + public int LinksetChildIndex { get; set; } + + public BSLinkset.LinksetImplementation LinksetType { get; set; } + + public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, + OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) + : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical) { - BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG - int childrenBefore = Linkset.NumberOfChildren; // DEBUG - - Linkset = parent.Linkset.AddMeToLinkset(this); - - DetailLog("{0},BSPrimLinkable.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", - LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); - } - return; - } - - public override void delink() - { - // TODO: decide if this parent checking needs to happen at taint time - // Race condition here: if link() and delink() in same simulation tick, the delink will not happen - - BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG - int childrenBefore = Linkset.NumberOfChildren; // DEBUG - - Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime*/); - - DetailLog("{0},BSPrimLinkable.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", - LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); - return; - } - - // When simulator changes position, this might be moving a child of the linkset. - public override OMV.Vector3 Position - { - get { return base.Position; } - set - { - base.Position = value; - PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setPosition", delegate() - { - Linkset.UpdateProperties(UpdatedProperties.Position, this); - }); - } - } - - // When simulator changes orientation, this might be moving a child of the linkset. - public override OMV.Quaternion Orientation - { - get { return base.Orientation; } - set - { - base.Orientation = value; - PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setOrientation", delegate() - { - Linkset.UpdateProperties(UpdatedProperties.Orientation, this); - }); - } - } - - public override float TotalMass - { - get { return Linkset.LinksetMass; } - } - - public override OMV.Vector3 CenterOfMass - { - get { return Linkset.CenterOfMass; } - } - - public override OMV.Vector3 GeometricCenter - { - get { return Linkset.GeometricCenter; } - } - - // Refresh the linkset structure and parameters when the prim's physical parameters are changed. - public override void UpdatePhysicalParameters() - { - base.UpdatePhysicalParameters(); - // Recompute any linkset parameters. - // When going from non-physical to physical, this re-enables the constraints that - // had been automatically disabled when the mass was set to zero. - // For compound based linksets, this enables and disables interactions of the children. - if (Linkset != null) // null can happen during initialization + // Default linkset implementation for this prim + LinksetType = (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation; + + Linkset = BSLinkset.Factory(PhysScene, this); + Linkset.Refresh(this); - } - - // When the prim is made dynamic or static, the linkset needs to change. - protected override void MakeDynamic(bool makeStatic) - { - base.MakeDynamic(makeStatic); - if (Linkset != null) // null can happen during initialization - { - if (makeStatic) - Linkset.MakeStatic(this); - else - Linkset.MakeDynamic(this); } - } - - // Body is being taken apart. Remove physical dependencies and schedule a rebuild. - protected override void RemoveDependencies() - { - if (Linkset != null) - Linkset.RemoveDependencies(this); - base.RemoveDependencies(); - } - - // Called after a simulation step for the changes in physical object properties. - // Do any filtering/modification needed for linksets. - public override void UpdateProperties(EntityProperties entprop) - { - if (Linkset.IsRoot(this) || Linkset.ShouldReportPropertyUpdates(this)) + + public override void Destroy() { - // Properties are only updated for the roots of a linkset. - // TODO: this will have to change when linksets are articulated. - base.UpdateProperties(entprop); + Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime */); + base.Destroy(); } - /* - else + + public override void link(OpenSim.Region.PhysicsModules.SharedBase.PhysicsActor obj) { - // For debugging, report the movement of children - DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", - LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, - entprop.Acceleration, entprop.RotationalVelocity); - } - */ - // The linkset might like to know about changing locations - Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); - } - - // Called after a simulation step to post a collision with this object. - // This returns 'true' if the collision has been queued and the SendCollisions call must - // be made at the end of the simulation step. - public override bool Collide(BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) - { - bool ret = false; - // Ask the linkset if it wants to handle the collision - if (!Linkset.HandleCollide(this, collidee, contactPoint, contactNormal, pentrationDepth)) - { - // The linkset didn't handle it so pass the collision through normal processing - ret = base.Collide(collidee, contactPoint, contactNormal, pentrationDepth); - } - return ret; - } - - // A linkset reports any collision on any part of the linkset. - public long SomeCollisionSimulationStep = 0; - public override bool HasSomeCollision - { - get - { - return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding; - } - set - { - if (value) - SomeCollisionSimulationStep = PhysScene.SimulationStep; - else - SomeCollisionSimulationStep = 0; - - base.HasSomeCollision = value; - } - } - - // Convert the existing linkset of this prim into a new type. - public bool ConvertLinkset(BSLinkset.LinksetImplementation newType) - { - bool ret = false; - if (LinksetType != newType) - { - DetailLog("{0},BSPrimLinkable.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType); - - // Set the implementation type first so the call to BSLinkset.Factory gets the new type. - this.LinksetType = newType; - - BSLinkset oldLinkset = this.Linkset; - BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this); - - this.Linkset = newLinkset; - - // Pick up any physical dependencies this linkset might have in the physics engine. - oldLinkset.RemoveDependencies(this); - - // Create a list of the children (mainly because can't interate through a list that's changing) - List children = new List(); - oldLinkset.ForEachMember((child) => + BSPrimLinkable parent = obj as BSPrimLinkable; + if (parent != null) { - if (!oldLinkset.IsRoot(child)) - children.Add(child); - return false; // 'false' says to continue to next member - }); - - // Remove the children from the old linkset and add to the new (will be a new instance from the factory) - foreach (BSPrimLinkable child in children) - { - oldLinkset.RemoveMeFromLinkset(child, true /*inTaintTime*/); + BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG + int childrenBefore = Linkset.NumberOfChildren; // DEBUG + + Linkset = parent.Linkset.AddMeToLinkset(this); + + DetailLog("{0},BSPrimLinkable.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", + LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); } - foreach (BSPrimLinkable child in children) - { - newLinkset.AddMeToLinkset(child); - child.Linkset = newLinkset; - } - - // Force the shape and linkset to get reconstructed - newLinkset.Refresh(this); - this.ForceBodyShapeRebuild(true /* inTaintTime */); + return; } - return ret; - } - - #region Extension - public override object Extension(string pFunct, params object[] pParams) - { - DetailLog("{0} BSPrimLinkable.Extension,op={1},nParam={2}", LocalID, pFunct, pParams.Length); - object ret = null; - switch (pFunct) + + public override void delink() { - // physGetLinksetType(); - // pParams = [ BSPhysObject root, null ] - case ExtendedPhysics.PhysFunctGetLinksetType: + // TODO: decide if this parent checking needs to happen at taint time + // Race condition here: if link() and delink() in same simulation tick, the delink will not happen + + BSPhysObject parentBefore = Linkset.LinksetRoot; // DEBUG + int childrenBefore = Linkset.NumberOfChildren; // DEBUG + + Linkset = Linkset.RemoveMeFromLinkset(this, false /* inTaintTime*/); + + DetailLog("{0},BSPrimLinkable.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", + LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren); + return; + } + + // When simulator changes position, this might be moving a child of the linkset. + public override OMV.Vector3 Position + { + get { return base.Position; } + set { - ret = (object)LinksetType; - DetailLog("{0},BSPrimLinkable.Extension.physGetLinksetType,type={1}", LocalID, ret); - break; - } - // physSetLinksetType(type); - // pParams = [ BSPhysObject root, null, integer type ] - case ExtendedPhysics.PhysFunctSetLinksetType: - { - if (pParams.Length > 2) + base.Position = value; + PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setPosition", delegate() { - BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[2]; - if (Linkset.IsRoot(this)) - { - PhysScene.TaintedObject(LocalID, "BSPrim.PhysFunctSetLinksetType", delegate() - { - // Cause the linkset type to change - DetailLog("{0},BSPrimLinkable.Extension.physSetLinksetType, oldType={1},newType={2}", - LocalID, Linkset.LinksetImpl, linksetType); - ConvertLinkset(linksetType); - }); - } - ret = (object)(int)linksetType; - } - break; + Linkset.UpdateProperties(UpdatedProperties.Position, this); + }); } - // physChangeLinkType(linknum, typeCode); - // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ] - case ExtendedPhysics.PhysFunctChangeLinkType: - { - ret = Linkset.Extension(pFunct, pParams); - break; - } - // physGetLinkType(linknum); - // pParams = [ BSPhysObject root, BSPhysObject child ] - case ExtendedPhysics.PhysFunctGetLinkType: - { - ret = Linkset.Extension(pFunct, pParams); - break; - } - // physChangeLinkParams(linknum, [code, value, code, value, ...]); - // pParams = [ BSPhysObject root, BSPhysObject child, object[] [ string op, object opParam, string op, object opParam, ... ] ] - case ExtendedPhysics.PhysFunctChangeLinkParams: - { - ret = Linkset.Extension(pFunct, pParams); - break; - } - default: - ret = base.Extension(pFunct, pParams); - break; } - return ret; + + // When simulator changes orientation, this might be moving a child of the linkset. + public override OMV.Quaternion Orientation + { + get { return base.Orientation; } + set + { + base.Orientation = value; + PhysScene.TaintedObject(LocalID, "BSPrimLinkable.setOrientation", delegate() + { + Linkset.UpdateProperties(UpdatedProperties.Orientation, this); + }); + } + } + + public override float TotalMass + { + get { return Linkset.LinksetMass; } + } + + public override OMV.Vector3 CenterOfMass + { + get { return Linkset.CenterOfMass; } + } + + public override OMV.Vector3 GeometricCenter + { + get { return Linkset.GeometricCenter; } + } + + // Refresh the linkset structure and parameters when the prim's physical parameters are changed. + public override void UpdatePhysicalParameters() + { + base.UpdatePhysicalParameters(); + // Recompute any linkset parameters. + // When going from non-physical to physical, this re-enables the constraints that + // had been automatically disabled when the mass was set to zero. + // For compound based linksets, this enables and disables interactions of the children. + if (Linkset != null) // null can happen during initialization + Linkset.Refresh(this); + } + + // When the prim is made dynamic or static, the linkset needs to change. + protected override void MakeDynamic(bool makeStatic) + { + base.MakeDynamic(makeStatic); + if (Linkset != null) // null can happen during initialization + { + if (makeStatic) + Linkset.MakeStatic(this); + else + Linkset.MakeDynamic(this); + } + } + + // Body is being taken apart. Remove physical dependencies and schedule a rebuild. + protected override void RemoveDependencies() + { + if (Linkset != null) + Linkset.RemoveDependencies(this); + base.RemoveDependencies(); + } + + // Called after a simulation step for the changes in physical object properties. + // Do any filtering/modification needed for linksets. + public override void UpdateProperties(EntityProperties entprop) + { + if (Linkset.IsRoot(this) || Linkset.ShouldReportPropertyUpdates(this)) + { + // Properties are only updated for the roots of a linkset. + // TODO: this will have to change when linksets are articulated. + base.UpdateProperties(entprop); + } + /* + else + { + // For debugging, report the movement of children + DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}", + LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, + entprop.Acceleration, entprop.RotationalVelocity); + } + */ + // The linkset might like to know about changing locations + Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); + } + + // Called after a simulation step to post a collision with this object. + // This returns 'true' if the collision has been queued and the SendCollisions call must + // be made at the end of the simulation step. + public override bool Collide(BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) + { + bool ret = false; + // Ask the linkset if it wants to handle the collision + if (!Linkset.HandleCollide(this, collidee, contactPoint, contactNormal, pentrationDepth)) + { + // The linkset didn't handle it so pass the collision through normal processing + ret = base.Collide(collidee, contactPoint, contactNormal, pentrationDepth); + } + return ret; + } + + // A linkset reports any collision on any part of the linkset. + public long SomeCollisionSimulationStep = 0; + public override bool HasSomeCollision + { + get + { + return (SomeCollisionSimulationStep == PhysScene.SimulationStep) || base.IsColliding; + } + set + { + if (value) + SomeCollisionSimulationStep = PhysScene.SimulationStep; + else + SomeCollisionSimulationStep = 0; + + base.HasSomeCollision = value; + } + } + + // Convert the existing linkset of this prim into a new type. + public bool ConvertLinkset(BSLinkset.LinksetImplementation newType) + { + bool ret = false; + if (LinksetType != newType) + { + DetailLog("{0},BSPrimLinkable.ConvertLinkset,oldT={1},newT={2}", LocalID, LinksetType, newType); + + // Set the implementation type first so the call to BSLinkset.Factory gets the new type. + this.LinksetType = newType; + + BSLinkset oldLinkset = this.Linkset; + BSLinkset newLinkset = BSLinkset.Factory(PhysScene, this); + + this.Linkset = newLinkset; + + // Pick up any physical dependencies this linkset might have in the physics engine. + oldLinkset.RemoveDependencies(this); + + // Create a list of the children (mainly because can't interate through a list that's changing) + List children = new List(); + oldLinkset.ForEachMember((child) => + { + if (!oldLinkset.IsRoot(child)) + children.Add(child); + return false; // 'false' says to continue to next member + }); + + // Remove the children from the old linkset and add to the new (will be a new instance from the factory) + foreach (BSPrimLinkable child in children) + { + oldLinkset.RemoveMeFromLinkset(child, true /*inTaintTime*/); + } + foreach (BSPrimLinkable child in children) + { + newLinkset.AddMeToLinkset(child); + child.Linkset = newLinkset; + } + + // Force the shape and linkset to get reconstructed + newLinkset.Refresh(this); + this.ForceBodyShapeRebuild(true /* inTaintTime */); + } + return ret; + } + + #region Extension + public override object Extension(string pFunct, params object[] pParams) + { + DetailLog("{0} BSPrimLinkable.Extension,op={1},nParam={2}", LocalID, pFunct, pParams.Length); + object ret = null; + switch (pFunct) + { + // physGetLinksetType(); + // pParams = [ BSPhysObject root, null ] + case ExtendedPhysics.PhysFunctGetLinksetType: + { + ret = (object)LinksetType; + DetailLog("{0},BSPrimLinkable.Extension.physGetLinksetType,type={1}", LocalID, ret); + break; + } + // physSetLinksetType(type); + // pParams = [ BSPhysObject root, null, integer type ] + case ExtendedPhysics.PhysFunctSetLinksetType: + { + if (pParams.Length > 2) + { + BSLinkset.LinksetImplementation linksetType = (BSLinkset.LinksetImplementation)pParams[2]; + if (Linkset.IsRoot(this)) + { + PhysScene.TaintedObject(LocalID, "BSPrim.PhysFunctSetLinksetType", delegate() + { + // Cause the linkset type to change + DetailLog("{0},BSPrimLinkable.Extension.physSetLinksetType, oldType={1},newType={2}", + LocalID, Linkset.LinksetImpl, linksetType); + ConvertLinkset(linksetType); + }); + } + ret = (object)(int)linksetType; + } + break; + } + // physChangeLinkType(linknum, typeCode); + // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ] + case ExtendedPhysics.PhysFunctChangeLinkType: + { + ret = Linkset.Extension(pFunct, pParams); + break; + } + // physGetLinkType(linknum); + // pParams = [ BSPhysObject root, BSPhysObject child ] + case ExtendedPhysics.PhysFunctGetLinkType: + { + ret = Linkset.Extension(pFunct, pParams); + break; + } + // physChangeLinkParams(linknum, [code, value, code, value, ...]); + // pParams = [ BSPhysObject root, BSPhysObject child, object[] [ string op, object opParam, string op, object opParam, ... ] ] + case ExtendedPhysics.PhysFunctChangeLinkParams: + { + ret = Linkset.Extension(pFunct, pParams); + break; + } + default: + ret = base.Extension(pFunct, pParams); + break; + } + return ret; + } + #endregion // Extension } - #endregion // Extension -} } diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs index 86bf23f226..3be92f24d9 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapeCollection.cs @@ -33,390 +33,390 @@ using OpenSim.Region.PhysicsModules.SharedBase; namespace OpenSim.Region.PhysicsModule.BulletS { -public sealed class BSShapeCollection : IDisposable -{ + public sealed class BSShapeCollection : IDisposable + { #pragma warning disable 414 - private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; + private static string LogHeader = "[BULLETSIM SHAPE COLLECTION]"; #pragma warning restore 414 - private BSScene m_physicsScene { get; set; } - - private Object m_collectionActivityLock = new Object(); - - private bool DDetail = false; - - public BSShapeCollection(BSScene physScene) - { - m_physicsScene = physScene; - // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) - // While detailed debugging is still active, this is better than commenting out all the - // DetailLog statements. When debugging slows down, this and the protected logging - // statements can be commented/removed. - DDetail = true; - } - - public void Dispose() - { - // TODO!!!!!!!!! - } - - // Callbacks called just before either the body or shape is destroyed. - // Mostly used for changing bodies out from under Linksets. - // Useful for other cases where parameters need saving. - // Passing 'null' says no callback. - public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape); - - // Called to update/change the body and shape for an object. - // The object has some shape and body on it. Here we decide if that is the correct shape - // for the current state of the object (static/dynamic/...). - // If bodyCallback is not null, it is called if either the body or the shape are changed - // so dependencies (like constraints) can be removed before the physical object is dereferenced. - // Return 'true' if either the body or the shape changed. - // Called at taint-time. - public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback) - { - bool ret = false; - - // This lock could probably be pushed down lower but building shouldn't take long - lock (m_collectionActivityLock) + private BSScene m_physicsScene { get; set; } + + private Object m_collectionActivityLock = new Object(); + + private bool DDetail = false; + + public BSShapeCollection(BSScene physScene) { - // Do we have the correct geometry for this type of object? - // Updates prim.BSShape with information/pointers to shape. - // Returns 'true' of BSShape is changed to a new shape. - bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback); - // If we had to select a new shape geometry for the object, - // rebuild the body around it. - // Updates prim.BSBody with information/pointers to requested body - // Returns 'true' if BSBody was changed. - bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback); - ret = newGeom || newBody; + m_physicsScene = physScene; + // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) + // While detailed debugging is still active, this is better than commenting out all the + // DetailLog statements. When debugging slows down, this and the protected logging + // statements can be commented/removed. + DDetail = true; } - DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", - prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape); - - return ret; - } - - public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) - { - return GetBodyAndShape(forceRebuild, sim, prim, null); - } - - // If the existing prim's shape is to be replaced, remove the tie to the existing shape - // before replacing it. - private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) - { - if (prim.PhysShape.HasPhysicalShape) + + public void Dispose() { - if (shapeCallback != null) - shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo); - prim.PhysShape.Dereference(m_physicsScene); + // TODO!!!!!!!!! } - prim.PhysShape = new BSShapeNull(); - } - - // Create the geometry information in Bullet for later use. - // The objects needs a hull if it's physical otherwise a mesh is enough. - // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls, - // shared geometries will be used. If the parameters of the existing shape are the same - // as this request, the shape is not rebuilt. - // Info in prim.BSShape is updated to the new shape. - // Returns 'true' if the geometry was rebuilt. - // Called at taint-time! - public const int AvatarShapeCapsule = 0; - public const int AvatarShapeCube = 1; - public const int AvatarShapeOvoid = 2; - public const int AvatarShapeMesh = 3; - private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback) - { - bool ret = false; - bool haveShape = false; - bool nativeShapePossible = true; - PrimitiveBaseShape pbs = prim.BaseShape; - - // Kludge to create the capsule for the avatar. - // TDOD: Remove/redo this when BSShapeAvatar is working!! - BSCharacter theChar = prim as BSCharacter; - if (theChar != null) + + // Callbacks called just before either the body or shape is destroyed. + // Mostly used for changing bodies out from under Linksets. + // Useful for other cases where parameters need saving. + // Passing 'null' says no callback. + public delegate void PhysicalDestructionCallback(BulletBody pBody, BulletShape pShape); + + // Called to update/change the body and shape for an object. + // The object has some shape and body on it. Here we decide if that is the correct shape + // for the current state of the object (static/dynamic/...). + // If bodyCallback is not null, it is called if either the body or the shape are changed + // so dependencies (like constraints) can be removed before the physical object is dereferenced. + // Return 'true' if either the body or the shape changed. + // Called at taint-time. + public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim, PhysicalDestructionCallback bodyCallback) { - DereferenceExistingShape(prim, shapeCallback); - switch (BSParam.AvatarShape) + bool ret = false; + + // This lock could probably be pushed down lower but building shouldn't take long + lock (m_collectionActivityLock) { - case AvatarShapeCapsule: - prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, - BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE); - ret = true; - haveShape = true; - break; - case AvatarShapeCube: - prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, - BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_CAPSULE); - ret = true; - haveShape = true; - break; - case AvatarShapeOvoid: - // Saddly, Bullet doesn't scale spheres so this doesn't work as an avatar shape - prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, - BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_CAPSULE); - ret = true; - haveShape = true; - break; - case AvatarShapeMesh: - break; - default: - break; + // Do we have the correct geometry for this type of object? + // Updates prim.BSShape with information/pointers to shape. + // Returns 'true' of BSShape is changed to a new shape. + bool newGeom = CreateGeom(forceRebuild, prim, bodyCallback); + // If we had to select a new shape geometry for the object, + // rebuild the body around it. + // Updates prim.BSBody with information/pointers to requested body + // Returns 'true' if BSBody was changed. + bool newBody = CreateBody((newGeom || forceRebuild), prim, m_physicsScene.World, bodyCallback); + ret = newGeom || newBody; } + DetailLog("{0},BSShapeCollection.GetBodyAndShape,taintExit,force={1},ret={2},body={3},shape={4}", + prim.LocalID, forceRebuild, ret, prim.PhysBody, prim.PhysShape); + + return ret; } - - // If the prim attributes are simple, this could be a simple Bullet native shape - // Native shapes work whether to object is static or physical. - if (!haveShape - && nativeShapePossible - && pbs != null - && PrimHasNoCuts(pbs) - && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) ) - ) + + public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim) + { + return GetBodyAndShape(forceRebuild, sim, prim, null); + } + + // If the existing prim's shape is to be replaced, remove the tie to the existing shape + // before replacing it. + private void DereferenceExistingShape(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) { - // Get the scale of any existing shape so we can see if the new shape is same native type and same size. - OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; if (prim.PhysShape.HasPhysicalShape) - scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo); - - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", - prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType); - - // It doesn't look like Bullet scales native spheres so make sure the scales are all equal - if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) - && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) { - haveShape = true; - if (forceRebuild - || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE + if (shapeCallback != null) + shapeCallback(prim.PhysBody, prim.PhysShape.physShapeInfo); + prim.PhysShape.Dereference(m_physicsScene); + } + prim.PhysShape = new BSShapeNull(); + } + + // Create the geometry information in Bullet for later use. + // The objects needs a hull if it's physical otherwise a mesh is enough. + // if 'forceRebuild' is true, the geometry is unconditionally rebuilt. For meshes and hulls, + // shared geometries will be used. If the parameters of the existing shape are the same + // as this request, the shape is not rebuilt. + // Info in prim.BSShape is updated to the new shape. + // Returns 'true' if the geometry was rebuilt. + // Called at taint-time! + public const int AvatarShapeCapsule = 0; + public const int AvatarShapeCube = 1; + public const int AvatarShapeOvoid = 2; + public const int AvatarShapeMesh = 3; + private bool CreateGeom(bool forceRebuild, BSPhysObject prim, PhysicalDestructionCallback shapeCallback) + { + bool ret = false; + bool haveShape = false; + bool nativeShapePossible = true; + PrimitiveBaseShape pbs = prim.BaseShape; + + // Kludge to create the capsule for the avatar. + // TDOD: Remove/redo this when BSShapeAvatar is working!! + BSCharacter theChar = prim as BSCharacter; + if (theChar != null) + { + DereferenceExistingShape(prim, shapeCallback); + switch (BSParam.AvatarShape) + { + case AvatarShapeCapsule: + prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, + BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE); + ret = true; + haveShape = true; + break; + case AvatarShapeCube: + prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, + BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_CAPSULE); + ret = true; + haveShape = true; + break; + case AvatarShapeOvoid: + // Saddly, Bullet doesn't scale spheres so this doesn't work as an avatar shape + prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, + BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_CAPSULE); + ret = true; + haveShape = true; + break; + case AvatarShapeMesh: + break; + default: + break; + } + } + + // If the prim attributes are simple, this could be a simple Bullet native shape + // Native shapes work whether to object is static or physical. + if (!haveShape + && nativeShapePossible + && pbs != null + && PrimHasNoCuts(pbs) + && ( !pbs.SculptEntry || (pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim) ) + ) + { + // Get the scale of any existing shape so we can see if the new shape is same native type and same size. + OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; + if (prim.PhysShape.HasPhysicalShape) + scaleOfExistingShape = m_physicsScene.PE.GetLocalScaling(prim.PhysShape.physShapeInfo); + + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", + prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.physShapeInfo.shapeType); + + // It doesn't look like Bullet scales native spheres so make sure the scales are all equal + if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) + && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) + { + haveShape = true; + if (forceRebuild + || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_SPHERE + ) + { + DereferenceExistingShape(prim, shapeCallback); + prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, + BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE); + ret = true; + } + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", + prim.LocalID, forceRebuild, ret, prim.PhysShape); + } + // If we didn't make a sphere, maybe a box will work. + if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) + { + haveShape = true; + if (forceRebuild + || prim.Scale != scaleOfExistingShape + || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX + ) + { + DereferenceExistingShape(prim, shapeCallback); + prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, + BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + ret = true; + } + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", + prim.LocalID, forceRebuild, ret, prim.PhysShape); + } + } + + // If a simple shape is not happening, create a mesh and possibly a hull. + if (!haveShape && pbs != null) + { + ret = CreateGeomMeshOrHull(prim, shapeCallback); + } + + m_physicsScene.PE.ResetBroadphasePool(m_physicsScene.World); // DEBUG DEBUG + + return ret; + } + + // return 'true' if this shape description does not include any cutting or twisting. + public static bool PrimHasNoCuts(PrimitiveBaseShape pbs) + { + return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 + && pbs.ProfileHollow == 0 + && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 + && pbs.PathBegin == 0 && pbs.PathEnd == 0 + && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 + && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 + && pbs.PathShearX == 0 && pbs.PathShearY == 0; + } + + // return 'true' if the prim's shape was changed. + private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) + { + + bool ret = false; + // Note that if it's a native shape, the check for physical/non-physical is not + // made. Native shapes work in either case. + if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) + { + // Use a simple, single mesh convex hull shape if the object is simple enough + BSShape potentialHull = null; + + PrimitiveBaseShape pbs = prim.BaseShape; + // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists) + if (BSParam.ShouldUseSingleConvexHullForPrims + && pbs != null + && !pbs.SculptEntry + && PrimHasNoCuts(pbs) ) { - DereferenceExistingShape(prim, shapeCallback); - prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, - BSPhysicsShapeType.SHAPE_SPHERE, FixedShapeKey.KEY_SPHERE); - ret = true; + potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim); } - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},rebuilt={2},shape={3}", - prim.LocalID, forceRebuild, ret, prim.PhysShape); - } - // If we didn't make a sphere, maybe a box will work. - if (!haveShape && pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) - { - haveShape = true; - if (forceRebuild - || prim.Scale != scaleOfExistingShape - || prim.PhysShape.ShapeType != BSPhysicsShapeType.SHAPE_BOX - ) + // Use the GImpact shape if it is a prim that has some concaveness + if (potentialHull == null + && BSParam.ShouldUseGImpactShapeForPrims + && pbs != null + && !pbs.SculptEntry + ) + { + potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim); + } + // If not any of the simple cases, just make a hull + if (potentialHull == null) + { + potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); + } + + // If the current shape is not what is on the prim at the moment, time to change. + if (!prim.PhysShape.HasPhysicalShape + || potentialHull.ShapeType != prim.PhysShape.ShapeType + || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) { DereferenceExistingShape(prim, shapeCallback); - prim.PhysShape = BSShapeNative.GetReference(m_physicsScene, prim, - BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + prim.PhysShape = potentialHull; ret = true; } - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},rebuilt={2},shape={3}", - prim.LocalID, forceRebuild, ret, prim.PhysShape); + else + { + // The current shape on the prim is the correct one. We don't need the potential reference. + potentialHull.Dereference(m_physicsScene); + } + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape); + } + else + { + // Non-physical objects should be just meshes. + BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim); + // If the current shape is not what is on the prim at the moment, time to change. + if (!prim.PhysShape.HasPhysicalShape + || potentialMesh.ShapeType != prim.PhysShape.ShapeType + || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) + { + DereferenceExistingShape(prim, shapeCallback); + prim.PhysShape = potentialMesh; + ret = true; + } + else + { + // We don't need this reference to the mesh that is already being using. + potentialMesh.Dereference(m_physicsScene); + } + if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape); + } + return ret; + } + + // Track another user of a body. + // We presume the caller has allocated the body. + // Bodies only have one user so the body is just put into the world if not already there. + private void ReferenceBody(BulletBody body) + { + lock (m_collectionActivityLock) + { + if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); + if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body)) + { + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body); + if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); + } } } - - // If a simple shape is not happening, create a mesh and possibly a hull. - if (!haveShape && pbs != null) + + // Release the usage of a body. + // Called when releasing use of a BSBody. BSShape is handled separately. + // Called in taint time. + public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback ) { - ret = CreateGeomMeshOrHull(prim, shapeCallback); + if (!body.HasPhysicalBody) + return; + + lock (m_collectionActivityLock) + { + if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body); + // If the caller needs to know the old body is going away, pass the event up. + if (bodyCallback != null) + bodyCallback(body, null); + + // Removing an object not in the world is a NOOP + m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body); + + // Zero any reference to the shape so it is not freed when the body is deleted. + m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null); + + m_physicsScene.PE.DestroyObject(m_physicsScene.World, body); + } } - - m_physicsScene.PE.ResetBroadphasePool(m_physicsScene.World); // DEBUG DEBUG - - return ret; - } - - // return 'true' if this shape description does not include any cutting or twisting. - public static bool PrimHasNoCuts(PrimitiveBaseShape pbs) - { - return pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 - && pbs.ProfileHollow == 0 - && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 - && pbs.PathBegin == 0 && pbs.PathEnd == 0 - && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 - && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 - && pbs.PathShearX == 0 && pbs.PathShearY == 0; - } - - // return 'true' if the prim's shape was changed. - private bool CreateGeomMeshOrHull(BSPhysObject prim, PhysicalDestructionCallback shapeCallback) - { - - bool ret = false; - // Note that if it's a native shape, the check for physical/non-physical is not - // made. Native shapes work in either case. - if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects) + + // Create a body object in Bullet. + // Updates prim.BSBody with the information about the new body if one is created. + // Returns 'true' if an object was actually created. + // Called at taint-time. + private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback) { - // Use a simple, single mesh convex hull shape if the object is simple enough - BSShape potentialHull = null; - - PrimitiveBaseShape pbs = prim.BaseShape; - // Use a simple, one section convex shape for prims that are probably convex (no cuts or twists) - if (BSParam.ShouldUseSingleConvexHullForPrims - && pbs != null - && !pbs.SculptEntry - && PrimHasNoCuts(pbs) - ) + bool ret = false; + + // the mesh, hull or native shape must have already been created in Bullet + bool mustRebuild = !prim.PhysBody.HasPhysicalBody; + + // If there is an existing body, verify it's of an acceptable type. + // If not a solid object, body is a GhostObject. Otherwise a RigidBody. + if (!mustRebuild) { - potentialHull = BSShapeConvexHull.GetReference(m_physicsScene, false /* forceRebuild */, prim); + CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody); + if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY + || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) + { + // If the collisionObject is not the correct type for solidness, rebuild what's there + mustRebuild = true; + if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType); + } } - // Use the GImpact shape if it is a prim that has some concaveness - if (potentialHull == null - && BSParam.ShouldUseGImpactShapeForPrims - && pbs != null - && !pbs.SculptEntry - ) + + if (mustRebuild || forceRebuild) { - potentialHull = BSShapeGImpact.GetReference(m_physicsScene, false /* forceRebuild */, prim); - } - // If not any of the simple cases, just make a hull - if (potentialHull == null) - { - potentialHull = BSShapeHull.GetReference(m_physicsScene, false /*forceRebuild*/, prim); - } - - // If the current shape is not what is on the prim at the moment, time to change. - if (!prim.PhysShape.HasPhysicalShape - || potentialHull.ShapeType != prim.PhysShape.ShapeType - || potentialHull.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) - { - DereferenceExistingShape(prim, shapeCallback); - prim.PhysShape = potentialHull; + // Free any old body + DereferenceBody(prim.PhysBody, bodyCallback); + + BulletBody aBody; + if (prim.IsSolid) + { + aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); + if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody); + } + else + { + aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); + if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); + } + + ReferenceBody(aBody); + + prim.PhysBody = aBody; + ret = true; } - else - { - // The current shape on the prim is the correct one. We don't need the potential reference. - potentialHull.Dereference(m_physicsScene); - } - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1}", prim.LocalID, prim.PhysShape); + + return ret; } - else + + private void DetailLog(string msg, params Object[] args) { - // Non-physical objects should be just meshes. - BSShape potentialMesh = BSShapeMesh.GetReference(m_physicsScene, false /*forceRebuild*/, prim); - // If the current shape is not what is on the prim at the moment, time to change. - if (!prim.PhysShape.HasPhysicalShape - || potentialMesh.ShapeType != prim.PhysShape.ShapeType - || potentialMesh.physShapeInfo.shapeKey != prim.PhysShape.physShapeInfo.shapeKey) - { - DereferenceExistingShape(prim, shapeCallback); - prim.PhysShape = potentialMesh; - ret = true; - } - else - { - // We don't need this reference to the mesh that is already being using. - potentialMesh.Dereference(m_physicsScene); - } - if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1}", prim.LocalID, prim.PhysShape); + if (m_physicsScene.PhysicsLogging.Enabled) + m_physicsScene.DetailLog(msg, args); } - return ret; - } - - // Track another user of a body. - // We presume the caller has allocated the body. - // Bodies only have one user so the body is just put into the world if not already there. - private void ReferenceBody(BulletBody body) - { - lock (m_collectionActivityLock) - { - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); - if (!m_physicsScene.PE.IsInWorld(m_physicsScene.World, body)) - { - m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, body); - if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); - } - } - } - - // Release the usage of a body. - // Called when releasing use of a BSBody. BSShape is handled separately. - // Called in taint time. - public void DereferenceBody(BulletBody body, PhysicalDestructionCallback bodyCallback ) - { - if (!body.HasPhysicalBody) - return; - - lock (m_collectionActivityLock) - { - if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1}", body.ID, body); - // If the caller needs to know the old body is going away, pass the event up. - if (bodyCallback != null) - bodyCallback(body, null); - - // Removing an object not in the world is a NOOP - m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, body); - - // Zero any reference to the shape so it is not freed when the body is deleted. - m_physicsScene.PE.SetCollisionShape(m_physicsScene.World, body, null); - - m_physicsScene.PE.DestroyObject(m_physicsScene.World, body); - } - } - - // Create a body object in Bullet. - // Updates prim.BSBody with the information about the new body if one is created. - // Returns 'true' if an object was actually created. - // Called at taint-time. - private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, PhysicalDestructionCallback bodyCallback) - { - bool ret = false; - - // the mesh, hull or native shape must have already been created in Bullet - bool mustRebuild = !prim.PhysBody.HasPhysicalBody; - - // If there is an existing body, verify it's of an acceptable type. - // If not a solid object, body is a GhostObject. Otherwise a RigidBody. - if (!mustRebuild) - { - CollisionObjectTypes bodyType = (CollisionObjectTypes)m_physicsScene.PE.GetBodyType(prim.PhysBody); - if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY - || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) - { - // If the collisionObject is not the correct type for solidness, rebuild what's there - mustRebuild = true; - if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,forceRebuildBecauseChangingBodyType,bodyType={1}", prim.LocalID, bodyType); - } - } - - if (mustRebuild || forceRebuild) - { - // Free any old body - DereferenceBody(prim.PhysBody, bodyCallback); - - BulletBody aBody; - if (prim.IsSolid) - { - aBody = m_physicsScene.PE.CreateBodyFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,rigid,body={1}", prim.LocalID, aBody); - } - else - { - aBody = m_physicsScene.PE.CreateGhostFromShape(sim, prim.PhysShape.physShapeInfo, prim.LocalID, prim.RawPosition, prim.RawOrientation); - if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody); - } - - ReferenceBody(aBody); - - prim.PhysBody = aBody; - - ret = true; - } - - return ret; - } - - private void DetailLog(string msg, params Object[] args) - { - if (m_physicsScene.PhysicsLogging.Enabled) - m_physicsScene.DetailLog(msg, args); } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs index 3e2a82bb72..66c97aa214 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSShapes.cs @@ -38,1056 +38,1057 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -// Information class that holds stats for the shape. Which values mean -// something depends on the type of shape. -// This information is used for debugging and stats and is not used -// for operational things. -public class ShapeInfoInfo -{ - public int Vertices { get; set; } - private int m_hullCount; - private int[] m_verticesPerHull; - public ShapeInfoInfo() + // Information class that holds stats for the shape. Which values mean + // something depends on the type of shape. + // This information is used for debugging and stats and is not used + // for operational things. + public class ShapeInfoInfo { - Vertices = 0; - m_hullCount = 0; - m_verticesPerHull = null; - } - public int HullCount - { - set + public int Vertices { get; set; } + private int m_hullCount; + private int[] m_verticesPerHull; + public ShapeInfoInfo() { - m_hullCount = value; - m_verticesPerHull = new int[m_hullCount]; - Array.Clear(m_verticesPerHull, 0, m_hullCount); + Vertices = 0; + m_hullCount = 0; + m_verticesPerHull = null; } - get { return m_hullCount; } - } - public void SetVerticesPerHull(int hullNum, int vertices) - { - if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length) + public int HullCount { - m_verticesPerHull[hullNum] = vertices; - } - } - public int GetVerticesPerHull(int hullNum) - { - if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length) - { - return m_verticesPerHull[hullNum]; - } - return 0; - } - public override string ToString() - { - StringBuilder buff = new StringBuilder(); - // buff.Append("ShapeInfo=<"); - buff.Append("<"); - if (Vertices > 0) - { - buff.Append("verts="); - buff.Append(Vertices.ToString()); - } - - if (Vertices > 0 && HullCount > 0) buff.Append(","); - - if (HullCount > 0) - { - buff.Append("nHulls="); - buff.Append(HullCount.ToString()); - buff.Append(","); - buff.Append("hullVerts="); - for (int ii = 0; ii < HullCount; ii++) + set { - if (ii != 0) buff.Append(","); - buff.Append(GetVerticesPerHull(ii).ToString()); + m_hullCount = value; + m_verticesPerHull = new int[m_hullCount]; + Array.Clear(m_verticesPerHull, 0, m_hullCount); + } + get { return m_hullCount; } + } + public void SetVerticesPerHull(int hullNum, int vertices) + { + if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length) + { + m_verticesPerHull[hullNum] = vertices; } } - buff.Append(">"); - return buff.ToString(); - } -} - -public abstract class BSShape -{ - private static string LogHeader = "[BULLETSIM SHAPE]"; - - public int referenceCount { get; set; } - public DateTime lastReferenced { get; set; } - public BulletShape physShapeInfo { get; set; } - public ShapeInfoInfo shapeInfo { get; private set; } - - public BSShape() - { - referenceCount = 1; - lastReferenced = DateTime.Now; - physShapeInfo = new BulletShape(); - shapeInfo = new ShapeInfoInfo(); - } - public BSShape(BulletShape pShape) - { - referenceCount = 1; - lastReferenced = DateTime.Now; - physShapeInfo = pShape; - shapeInfo = new ShapeInfoInfo(); - } - - // Get another reference to this shape. - public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim); - - // Called when this shape is being used again. - // Used internally. External callers should call instance.GetReference() to properly copy/reference - // the shape. - protected virtual void IncrementReference() - { - referenceCount++; - lastReferenced = DateTime.Now; - } - - // Called when this shape is done being used. - protected virtual void DecrementReference() - { - referenceCount--; - lastReferenced = DateTime.Now; - } - - // Release the use of a physical shape. - public abstract void Dereference(BSScene physicsScene); - - // Return 'true' if there is an allocated physics physical shape under this class instance. - public virtual bool HasPhysicalShape - { - get + public int GetVerticesPerHull(int hullNum) { - if (physShapeInfo != null) - return physShapeInfo.HasPhysicalShape; - return false; + if (m_verticesPerHull != null && hullNum < m_verticesPerHull.Length) + { + return m_verticesPerHull[hullNum]; + } + return 0; + } + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + // buff.Append("ShapeInfo=<"); + buff.Append("<"); + if (Vertices > 0) + { + buff.Append("verts="); + buff.Append(Vertices.ToString()); + } + + if (Vertices > 0 && HullCount > 0) buff.Append(","); + + if (HullCount > 0) + { + buff.Append("nHulls="); + buff.Append(HullCount.ToString()); + buff.Append(","); + buff.Append("hullVerts="); + for (int ii = 0; ii < HullCount; ii++) + { + if (ii != 0) buff.Append(","); + buff.Append(GetVerticesPerHull(ii).ToString()); + } + } + buff.Append(">"); + return buff.ToString(); } } - public virtual BSPhysicsShapeType ShapeType + + public abstract class BSShape { - get + private static string LogHeader = "[BULLETSIM SHAPE]"; + + public int referenceCount { get; set; } + public DateTime lastReferenced { get; set; } + public BulletShape physShapeInfo { get; set; } + public ShapeInfoInfo shapeInfo { get; private set; } + + public BSShape() { - BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; - if (physShapeInfo != null && physShapeInfo.HasPhysicalShape) - ret = physShapeInfo.shapeType; + referenceCount = 1; + lastReferenced = DateTime.Now; + physShapeInfo = new BulletShape(); + shapeInfo = new ShapeInfoInfo(); + } + public BSShape(BulletShape pShape) + { + referenceCount = 1; + lastReferenced = DateTime.Now; + physShapeInfo = pShape; + shapeInfo = new ShapeInfoInfo(); + } + + // Get another reference to this shape. + public abstract BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim); + + // Called when this shape is being used again. + // Used internally. External callers should call instance.GetReference() to properly copy/reference + // the shape. + protected virtual void IncrementReference() + { + referenceCount++; + lastReferenced = DateTime.Now; + } + + // Called when this shape is done being used. + protected virtual void DecrementReference() + { + referenceCount--; + lastReferenced = DateTime.Now; + } + + // Release the use of a physical shape. + public abstract void Dereference(BSScene physicsScene); + + // Return 'true' if there is an allocated physics physical shape under this class instance. + public virtual bool HasPhysicalShape + { + get + { + if (physShapeInfo != null) + return physShapeInfo.HasPhysicalShape; + return false; + } + } + public virtual BSPhysicsShapeType ShapeType + { + get + { + BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; + if (physShapeInfo != null && physShapeInfo.HasPhysicalShape) + ret = physShapeInfo.shapeType; + return ret; + } + } + + // Returns a string for debugging that uniquily identifies the memory used by this instance + public virtual string AddrString + { + get + { + if (physShapeInfo != null) + return physShapeInfo.AddrString; + return "unknown"; + } + } + + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + if (physShapeInfo == null) + { + buff.Append(""); + return buff.ToString(); + } + + #region Common shape routines + // Create a hash of all the shape parameters to be used as a key for this particular shape. + public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) + { + // level of detail based on size and type of the object + float lod = BSParam.MeshLOD; + if (pbs.SculptEntry) + lod = BSParam.SculptLOD; + + // Mega prims usually get more detail because one can interact with shape approximations at this size. + float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); + if (maxAxis > BSParam.MeshMegaPrimThreshold) + lod = BSParam.MeshMegaPrimLOD; + + retLod = lod; + return pbs.GetMeshKey(size, lod); + } + + // The creation of a mesh or hull can fail if an underlying asset is not available. + // There are two cases: 1) the asset is not in the cache and it needs to be fetched; + // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). + // The first case causes the asset to be fetched. The second case requires + // us to not loop forever. + // Called after creating a physical mesh or hull. If the physical shape was created, + // just return. + public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim) + { + // If the shape was successfully created, nothing more to do + if (newShape.HasPhysicalShape) + return newShape; + + // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been + // fetched but we end up here again, the meshing of the asset must have failed. + // Prevent trying to keep fetching the mesh by declaring failure. + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) + { + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; + physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}", + LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}", + prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + } + else + { + // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset + if (prim.BaseShape.SculptEntry + && !prim.AssetFailed() + && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting + && prim.BaseShape.SculptTexture != OMV.UUID.Zero + ) + { + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}", + prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); + // Multiple requestors will know we're waiting for this asset + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; + + BSPhysObject xprim = prim; + RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod; + if (assetProvider != null) + { + BSPhysObject yprim = xprim; // probably not necessary, but, just in case. + assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) + { + // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID); + bool assetFound = false; + string mismatchIDs = String.Empty; // DEBUG DEBUG + if (asset != null && yprim.BaseShape.SculptEntry) + { + if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) + { + yprim.BaseShape.SculptData = asset.Data; + // This will cause the prim to see that the filler shape is not the right + // one and try again to build the object. + // No race condition with the normal shape setting since the rebuild is at taint time. + yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; + yprim.ForceBodyShapeRebuild(false /* inTaintTime */); + assetFound = true; + } + else + { + mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; + } + } + if (!assetFound) + { + yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; + } + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}", + yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); + }); + } + else + { + xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; + physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", + LogHeader, physicsScene.PhysicsSceneName); + } + } + else + { + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) + { + physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}", + LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}", + prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + } + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing) + { + physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}", + LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}", + prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); + } + } + } + + // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. + BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID); + + return fillShape.physShapeInfo; + } + + public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim) + { + StringBuilder buff = new StringBuilder(prim.PhysObjectName); + buff.Append("/pos="); + buff.Append(prim.RawPosition.ToString()); + if (pScene != null) + { + buff.Append("/rgn="); + buff.Append(pScene.PhysicsSceneName); + } + return buff.ToString(); + } + + #endregion // Common shape routines + } + + // ============================================================================================================ + public class BSShapeNull : BSShape + { + public BSShapeNull() : base() + { + } + public static BSShape GetReference() { return new BSShapeNull(); } + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); } + public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } + } + + // ============================================================================================================ + // BSShapeNative is a wrapper for a Bullet 'native' shape -- cube and sphere. + // They are odd in that they don't allocate meshes but are computated/procedural. + // This means allocation and freeing is different than meshes. + public class BSShapeNative : BSShape + { + private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; + public BSShapeNative(BulletShape pShape) : base(pShape) + { + } + + public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, + BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) + { + // Native shapes are not shared and are always built anew. + return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); + } + + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) + { + // Native shapes are not shared so we return a new shape. + BSShape ret = null; + lock (physShapeInfo) + { + ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim, + physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey)); + } + return ret; + } + + // Make this reference to the physical shape go away since native shapes are not shared. + public override void Dereference(BSScene physicsScene) + { + // Native shapes are not tracked and are released immediately + lock (physShapeInfo) + { + if (physShapeInfo.HasPhysicalShape) + { + physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); + physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); + } + physShapeInfo.Clear(); + // Garbage collection will free up this instance. + } + } + + private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim, + BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) + { + BulletShape newShape; + + ShapeData nativeShapeData = new ShapeData(); + nativeShapeData.Type = shapeType; + nativeShapeData.ID = prim.LocalID; + nativeShapeData.Scale = prim.Scale; + nativeShapeData.Size = prim.Scale; + nativeShapeData.MeshKey = (ulong)shapeKey; + nativeShapeData.HullKey = (ulong)shapeKey; + + if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) + { + newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); + physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale); + } + else + { + newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); + } + if (!newShape.HasPhysicalShape) + { + physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", + LogHeader, prim.LocalID, shapeType); + } + newShape.shapeType = shapeType; + newShape.isNativeShape = true; + newShape.shapeKey = (UInt64)shapeKey; + return newShape; + } + + } + + // ============================================================================================================ + // BSShapeMesh is a simple mesh. + public class BSShapeMesh : BSShape + { + private static string LogHeader = "[BULLETSIM SHAPE MESH]"; + public static Dictionary Meshes = new Dictionary(); + + public BSShapeMesh(BulletShape pShape) : base(pShape) + { + } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + float lod; + System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + + BSShapeMesh retMesh = null; + lock (Meshes) + { + if (Meshes.TryGetValue(newMeshKey, out retMesh)) + { + // The mesh has already been created. Return a new reference to same. + retMesh.IncrementReference(); + } + else + { + retMesh = new BSShapeMesh(new BulletShape()); + // An instance of this mesh has not been created. Build and remember same. + BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); + + // Check to see if mesh was created (might require an asset). + newShape = VerifyMeshCreated(physicsScene, newShape, prim); + if (!newShape.isNativeShape || prim.AssetFailed() ) + { + // If a mesh was what was created, remember the built shape for later sharing. + // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh. + Meshes.Add(newMeshKey, retMesh); + } + + retMesh.physShapeInfo = newShape; + } + } + physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod); + return retMesh; + } + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) + { + BSShape ret = null; + // If the underlying shape is native, the actual shape has not been build (waiting for asset) + // and we must create a copy of the native shape since they are never shared. + if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) + { + // TODO: decide when the native shapes should be freed. Check in Dereference? + ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + } + else + { + // Another reference to this shape is just counted. + IncrementReference(); + ret = this; + } + return ret; + } + public override void Dereference(BSScene physicsScene) + { + lock (Meshes) + { + this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this); + // TODO: schedule aging and destruction of unused meshes. + } + } + // Loop through all the known meshes and return the description based on the physical address. + public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh) + { + bool ret = false; + BSShapeMesh foundDesc = null; + lock (Meshes) + { + foreach (BSShapeMesh sm in Meshes.Values) + { + if (sm.physShapeInfo.ReferenceSame(pShape)) + { + foundDesc = sm; + ret = true; + break; + } + + } + } + outMesh = foundDesc; + return ret; + } + + public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices ); + private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, + PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) + { + return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, + (w, iC, i, vC, v) => + { + shapeInfo.Vertices = vC; + return physicsScene.PE.CreateMeshShape(w, iC, i, vC, v); + }); + } + + // Code that uses the mesher to create the index/vertices info for a trimesh shape. + // This is used by the passed 'makeShape' call to create the Bullet mesh shape. + // The actual build call is passed so this logic can be used by several of the shapes that use a + // simple mesh as their base shape. + public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, + PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape) + { + BulletShape newShape = new BulletShape(); + + IMesh meshData = null; + lock (physicsScene.mesher) + { + meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, + false, // say it is not physical so a bounding box is not built + false, // do not cache the mesh and do not use previously built versions + false, + false + ); + } + + if (meshData != null) + { + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) + { + // Release the fetched asset data once it has been used. + pbs.SculptData = Array.Empty(); + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; + } + + int[] indices = meshData.getIndexListAsInt(); + int realIndicesIndex = indices.Length; + float[] verticesAsFloats = meshData.getVertexListAsFloat(); + + if (BSParam.ShouldRemoveZeroWidthTriangles) + { + // Remove degenerate triangles. These are triangles with two of the vertices + // are the same. This is complicated by the problem that vertices are not + // made unique in sculpties so we have to compare the values in the vertex. + realIndicesIndex = 0; + for (int tri = 0; tri < indices.Length; tri += 3) + { + // Compute displacements into vertex array for each vertex of the triangle + int v1 = indices[tri + 0] * 3; + int v2 = indices[tri + 1] * 3; + int v3 = indices[tri + 2] * 3; + // Check to see if any two of the vertices are the same + if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] + && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] + && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) + || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] + && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] + && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) + || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] + && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] + && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) ) + ) + { + // None of the vertices of the triangles are the same. This is a good triangle; + indices[realIndicesIndex + 0] = indices[tri + 0]; + indices[realIndicesIndex + 1] = indices[tri + 1]; + indices[realIndicesIndex + 2] = indices[tri + 2]; + realIndicesIndex += 3; + } + } + } + physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}", + BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); + + if (realIndicesIndex != 0) + { + newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); + } + else + { + // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh. + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; + physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) ); + physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey); + } + } + newShape.shapeKey = newMeshKey; + + return newShape; + } + } + + // ============================================================================================================ + // BSShapeHull is a physical shape representation htat is made up of many convex hulls. + // The convex hulls are either supplied with the asset or are approximated by one of the + // convex hull creation routines (in OpenSim or in Bullet). + public class BSShapeHull : BSShape + { + #pragma warning disable 414 + private static string LogHeader = "[BULLETSIM SHAPE HULL]"; + #pragma warning restore 414 + + public static Dictionary Hulls = new Dictionary(); + + + public BSShapeHull(BulletShape pShape) : base(pShape) + { + } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + float lod; + System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + + BSShapeHull retHull = null; + lock (Hulls) + { + if (Hulls.TryGetValue(newHullKey, out retHull)) + { + // The mesh has already been created. Return a new reference to same. + retHull.IncrementReference(); + } + else + { + retHull = new BSShapeHull(new BulletShape()); + // An instance of this mesh has not been created. Build and remember same. + BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod); + + // Check to see if hull was created (might require an asset). + newShape = VerifyMeshCreated(physicsScene, newShape, prim); + if (!newShape.isNativeShape || prim.AssetFailed()) + { + // If a mesh was what was created, remember the built shape for later sharing. + Hulls.Add(newHullKey, retHull); + } + retHull.physShapeInfo = newShape; + } + } + physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod); + return retHull; + } + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) + { + BSShape ret = null; + // If the underlying shape is native, the actual shape has not been build (waiting for asset) + // and we must create a copy of the native shape since they are never shared. + if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) + { + // TODO: decide when the native shapes should be freed. Check in Dereference? + ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); + } + else + { + // Another reference to this shape is just counted. + IncrementReference(); + ret = this; + } + return ret; + } + public override void Dereference(BSScene physicsScene) + { + lock (Hulls) + { + this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this); + // TODO: schedule aging and destruction of unused meshes. + } + } + + List m_hulls; + private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey, + PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) + { + BulletShape newShape = new BulletShape(); + + IMesh meshData = null; + List> allHulls = null; + lock (physicsScene.mesher) + { + // Pass true for physicalness as this prevents the creation of bounding box which is not needed + meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */, false, false); + + // If we should use the asset's hull info, fetch it out of the locked mesher + if (meshData != null && BSParam.ShouldUseAssetHulls) + { + Meshmerizer realMesher = physicsScene.mesher as Meshmerizer; + if (realMesher != null) + { + allHulls = realMesher.GetConvexHulls(size); + } + if (allHulls == null) + { + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID); + } + } + } + + // If there is hull data in the mesh asset, build the hull from that + if (allHulls != null && BSParam.ShouldUseAssetHulls) + { + int hullCount = allHulls.Count; + shapeInfo.HullCount = hullCount; + int totalVertices = 1; // include one for the count of the hulls + // Using the structure described for HACD hulls, create the memory sturcture + // to pass the hull data to the creater. + foreach (List hullVerts in allHulls) + { + totalVertices += 4; // add four for the vertex count and centroid + totalVertices += hullVerts.Count * 3; // one vertex is three dimensions + } + float[] convHulls = new float[totalVertices]; + + convHulls[0] = (float)hullCount; + int jj = 1; + int hullIndex = 0; + foreach (List hullVerts in allHulls) + { + convHulls[jj + 0] = hullVerts.Count; + convHulls[jj + 1] = 0f; // centroid x,y,z + convHulls[jj + 2] = 0f; + convHulls[jj + 3] = 0f; + jj += 4; + foreach (OMV.Vector3 oneVert in hullVerts) + { + convHulls[jj + 0] = oneVert.X; + convHulls[jj + 1] = oneVert.Y; + convHulls[jj + 2] = oneVert.Z; + jj += 3; + } + shapeInfo.SetVerticesPerHull(hullIndex, hullVerts.Count); + hullIndex++; + } + + // create the hull data structure in Bullet + newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); + + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}", + prim.LocalID, hullCount, totalVertices, newShape); + } + + // If no hull specified in the asset and we should use Bullet's HACD approximation... + if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD) + { + // Build the hull shape from an existing mesh shape. + // The mesh should have already been created in Bullet. + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID); + BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim); + + if (meshShape.physShapeInfo.HasPhysicalShape) + { + HACDParams parms = new HACDParams(); + parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull; + parms.minClusters = BSParam.BHullMinClusters; + parms.compacityWeight = BSParam.BHullCompacityWeight; + parms.volumeWeight = BSParam.BHullVolumeWeight; + parms.concavity = BSParam.BHullConcavity; + parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints); + parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints); + parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints); + parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin); + parms.whichHACD = 0; // Use the HACD routine that comes with Bullet + + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); + newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms); + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape); + + // Now done with the mesh shape. + shapeInfo.HullCount = 1; + BSShapeMesh maybeMesh = meshShape as BSShapeMesh; + if (maybeMesh != null) + shapeInfo.SetVerticesPerHull(0, maybeMesh.shapeInfo.Vertices); + meshShape.Dereference(physicsScene); + } + physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); + } + + // If no other hull specifications, use our HACD hull approximation. + if (!newShape.HasPhysicalShape && meshData != null) + { + if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) + { + // Release the fetched asset data once it has been used. + pbs.SculptData = Array.Empty(); + prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; + } + + int[] indices = meshData.getIndexListAsInt(); + List vertices = meshData.getVertexList(); + + //format conversion from IMesh format to DecompDesc format + List convIndices = new List(); + List convVertices = new List(); + for (int ii = 0; ii < indices.GetLength(0); ii++) + { + convIndices.Add(indices[ii]); + } + foreach (OMV.Vector3 vv in vertices) + { + convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); + } + + uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; + if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) + { + // Simple primitive shapes we know are convex so they are better implemented with + // fewer hulls. + // Check for simple shape (prim without cuts) and reduce split parameter if so. + if (BSShapeCollection.PrimHasNoCuts(pbs)) + { + maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; + } + } + + // setup and do convex hull conversion + m_hulls = new List(); + DecompDesc dcomp = new DecompDesc(); + dcomp.mIndices = convIndices; + dcomp.mVertices = convVertices; + dcomp.mDepth = maxDepthSplit; + dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; + dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; + dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; + dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; + ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); + // create the hull into the _hulls variable + convexBuilder.process(dcomp); + + physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", + BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); + + // Convert the vertices and indices for passing to unmanaged. + // The hull information is passed as a large floating point array. + // The format is: + // convHulls[0] = number of hulls + // convHulls[1] = number of vertices in first hull + // convHulls[2] = hull centroid X coordinate + // convHulls[3] = hull centroid Y coordinate + // convHulls[4] = hull centroid Z coordinate + // convHulls[5] = first hull vertex X + // convHulls[6] = first hull vertex Y + // convHulls[7] = first hull vertex Z + // convHulls[8] = second hull vertex X + // ... + // convHulls[n] = number of vertices in second hull + // convHulls[n+1] = second hull centroid X coordinate + // ... + // + // TODO: is is very inefficient. Someday change the convex hull generator to return + // data structures that do not need to be converted in order to pass to Bullet. + // And maybe put the values directly into pinned memory rather than marshaling. + int hullCount = m_hulls.Count; + int totalVertices = 1; // include one for the count of the hulls + foreach (ConvexResult cr in m_hulls) + { + totalVertices += 4; // add four for the vertex count and centroid + totalVertices += cr.HullIndices.Count * 3; // we pass just triangles + } + float[] convHulls = new float[totalVertices]; + + convHulls[0] = (float)hullCount; + int jj = 1; + foreach (ConvexResult cr in m_hulls) + { + // copy vertices for index access + float3[] verts = new float3[cr.HullVertices.Count]; + int kk = 0; + foreach (float3 ff in cr.HullVertices) + { + verts[kk++] = ff; + } + + // add to the array one hull's worth of data + convHulls[jj++] = cr.HullIndices.Count; + convHulls[jj++] = 0f; // centroid x,y,z + convHulls[jj++] = 0f; + convHulls[jj++] = 0f; + foreach (int ind in cr.HullIndices) + { + convHulls[jj++] = verts[ind].x; + convHulls[jj++] = verts[ind].y; + convHulls[jj++] = verts[ind].z; + } + } + // create the hull data structure in Bullet + newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); + } + newShape.shapeKey = newHullKey; + return newShape; + } + // Callback from convex hull creater with a newly created hull. + // Just add it to our collection of hulls for this shape. + private void HullReturn(ConvexResult result) + { + m_hulls.Add(result); + return; + } + // Loop through all the known hulls and return the description based on the physical address. + public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull) + { + bool ret = false; + BSShapeHull foundDesc = null; + lock (Hulls) + { + foreach (BSShapeHull sh in Hulls.Values) + { + if (sh.physShapeInfo.ReferenceSame(pShape)) + { + foundDesc = sh; + ret = true; + break; + } + + } + } + outHull = foundDesc; return ret; } } - // Returns a string for debugging that uniquily identifies the memory used by this instance - public virtual string AddrString + // ============================================================================================================ + // BSShapeCompound is a wrapper for the Bullet compound shape which is built from multiple, separate + // meshes. Used by BulletSim for complex shapes like linksets. + public class BSShapeCompound : BSShape { - get + private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; + public static Dictionary CompoundShapes = new Dictionary(); + + public BSShapeCompound(BulletShape pShape) : base(pShape) { - if (physShapeInfo != null) - return physShapeInfo.AddrString; - return "unknown"; } - } - - public override string ToString() - { - StringBuilder buff = new StringBuilder(); - if (physShapeInfo == null) + public static BSShape GetReference(BSScene physicsScene) { - buff.Append(""); - return buff.ToString(); - } - - #region Common shape routines - // Create a hash of all the shape parameters to be used as a key for this particular shape. - public static System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) - { - // level of detail based on size and type of the object - float lod = BSParam.MeshLOD; - if (pbs.SculptEntry) - lod = BSParam.SculptLOD; - - // Mega prims usually get more detail because one can interact with shape approximations at this size. - float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); - if (maxAxis > BSParam.MeshMegaPrimThreshold) - lod = BSParam.MeshMegaPrimLOD; - - retLod = lod; - return pbs.GetMeshKey(size, lod); - } - - // The creation of a mesh or hull can fail if an underlying asset is not available. - // There are two cases: 1) the asset is not in the cache and it needs to be fetched; - // and 2) the asset cannot be converted (like failed decompression of JPEG2000s). - // The first case causes the asset to be fetched. The second case requires - // us to not loop forever. - // Called after creating a physical mesh or hull. If the physical shape was created, - // just return. - public static BulletShape VerifyMeshCreated(BSScene physicsScene, BulletShape newShape, BSPhysObject prim) - { - // If the shape was successfully created, nothing more to do - if (newShape.HasPhysicalShape) - return newShape; - - // VerifyMeshCreated is called after trying to create the mesh. If we think the asset had been - // fetched but we end up here again, the meshing of the asset must have failed. - // Prevent trying to keep fetching the mesh by declaring failure. - if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) - { - prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; - physicsScene.Logger.WarnFormat("{0} Fetched asset would not mesh. prim={1}, texture={2}", - LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); - physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,setFailed,prim={1},tex={2}", - prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); - } - else - { - // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset - if (prim.BaseShape.SculptEntry - && !prim.AssetFailed() - && prim.PrimAssetState != BSPhysObject.PrimAssetCondition.Waiting - && prim.BaseShape.SculptTexture != OMV.UUID.Zero - ) - { - physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAsset,objNam={1},tex={2}", - prim.LocalID, prim.PhysObjectName, prim.BaseShape.SculptTexture); - // Multiple requestors will know we're waiting for this asset - prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Waiting; - - BSPhysObject xprim = prim; - RequestAssetDelegate assetProvider = physicsScene.RequestAssetMethod; - if (assetProvider != null) - { - BSPhysObject yprim = xprim; // probably not necessary, but, just in case. - assetProvider(yprim.BaseShape.SculptTexture, delegate(AssetBase asset) - { - // physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,assetProviderCallback", xprim.LocalID); - bool assetFound = false; - string mismatchIDs = String.Empty; // DEBUG DEBUG - if (asset != null && yprim.BaseShape.SculptEntry) - { - if (yprim.BaseShape.SculptTexture.ToString() == asset.ID) - { - yprim.BaseShape.SculptData = asset.Data; - // This will cause the prim to see that the filler shape is not the right - // one and try again to build the object. - // No race condition with the normal shape setting since the rebuild is at taint time. - yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.Fetched; - yprim.ForceBodyShapeRebuild(false /* inTaintTime */); - assetFound = true; - } - else - { - mismatchIDs = yprim.BaseShape.SculptTexture.ToString() + "/" + asset.ID; - } - } - if (!assetFound) - { - yprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; - } - physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,fetchAssetCallback,found={1},isSculpt={2},ids={3}", - yprim.LocalID, assetFound, yprim.BaseShape.SculptEntry, mismatchIDs ); - }); - } - else - { - xprim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedAssetFetch; - physicsScene.Logger.ErrorFormat("{0} Physical object requires asset but no asset provider. Name={1}", - LogHeader, physicsScene.PhysicsSceneName); - } - } - else - { - if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedAssetFetch) - { - physicsScene.Logger.WarnFormat("{0} Mesh failed to fetch asset. prim={1}, texture={2}", - LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); - physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailed,prim={1},tex={2}", - prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); - } - if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.FailedMeshing) - { - physicsScene.Logger.WarnFormat("{0} Mesh asset would not mesh. prim={1}, texture={2}", - LogHeader, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); - physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,wasFailedMeshing,prim={1},tex={2}", - prim.LocalID, UsefulPrimInfo(physicsScene, prim), prim.BaseShape.SculptTexture); - } - } - } - - // While we wait for the mesh defining asset to be loaded, stick in a simple box for the object. - BSShape fillShape = BSShapeNative.GetReference(physicsScene, prim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); - physicsScene.DetailLog("{0},BSShape.VerifyMeshCreated,boxTempShape", prim.LocalID); - - return fillShape.physShapeInfo; - } - - public static String UsefulPrimInfo(BSScene pScene, BSPhysObject prim) - { - StringBuilder buff = new StringBuilder(prim.PhysObjectName); - buff.Append("/pos="); - buff.Append(prim.RawPosition.ToString()); - if (pScene != null) - { - buff.Append("/rgn="); - buff.Append(pScene.PhysicsSceneName); - } - return buff.ToString(); - } - - #endregion // Common shape routines -} - -// ============================================================================================================ -public class BSShapeNull : BSShape -{ - public BSShapeNull() : base() - { - } - public static BSShape GetReference() { return new BSShapeNull(); } - public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) { return new BSShapeNull(); } - public override void Dereference(BSScene physicsScene) { /* The magic of garbage collection will make this go away */ } -} - -// ============================================================================================================ -// BSShapeNative is a wrapper for a Bullet 'native' shape -- cube and sphere. -// They are odd in that they don't allocate meshes but are computated/procedural. -// This means allocation and freeing is different than meshes. -public class BSShapeNative : BSShape -{ - private static string LogHeader = "[BULLETSIM SHAPE NATIVE]"; - public BSShapeNative(BulletShape pShape) : base(pShape) - { - } - - public static BSShape GetReference(BSScene physicsScene, BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) - { - // Native shapes are not shared and are always built anew. - return new BSShapeNative(CreatePhysicalNativeShape(physicsScene, prim, shapeType, shapeKey)); - } - - public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) - { - // Native shapes are not shared so we return a new shape. - BSShape ret = null; - lock (physShapeInfo) - { - ret = new BSShapeNative(CreatePhysicalNativeShape(pPhysicsScene, pPrim, - physShapeInfo.shapeType, (FixedShapeKey)physShapeInfo.shapeKey)); - } - return ret; - } - - // Make this reference to the physical shape go away since native shapes are not shared. - public override void Dereference(BSScene physicsScene) - { - // Native shapes are not tracked and are released immediately - lock (physShapeInfo) - { - if (physShapeInfo.HasPhysicalShape) - { - physicsScene.DetailLog("{0},BSShapeNative.Dereference,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); - physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); - } - physShapeInfo.Clear(); - // Garbage collection will free up this instance. - } - } - - private static BulletShape CreatePhysicalNativeShape(BSScene physicsScene, BSPhysObject prim, - BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) - { - BulletShape newShape; - - ShapeData nativeShapeData = new ShapeData(); - nativeShapeData.Type = shapeType; - nativeShapeData.ID = prim.LocalID; - nativeShapeData.Scale = prim.Scale; - nativeShapeData.Size = prim.Scale; - nativeShapeData.MeshKey = (ulong)shapeKey; - nativeShapeData.HullKey = (ulong)shapeKey; - - if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) - { - newShape = physicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale); - physicsScene.DetailLog("{0},BSShapeNative,capsule,scale={1}", prim.LocalID, prim.Scale); - } - else - { - newShape = physicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData); - } - if (!newShape.HasPhysicalShape) - { - physicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", - LogHeader, prim.LocalID, shapeType); - } - newShape.shapeType = shapeType; - newShape.isNativeShape = true; - newShape.shapeKey = (UInt64)shapeKey; - return newShape; - } - -} - -// ============================================================================================================ -// BSShapeMesh is a simple mesh. -public class BSShapeMesh : BSShape -{ - private static string LogHeader = "[BULLETSIM SHAPE MESH]"; - public static Dictionary Meshes = new Dictionary(); - - public BSShapeMesh(BulletShape pShape) : base(pShape) - { - } - public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) - { - float lod; - System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - - BSShapeMesh retMesh = null; - lock (Meshes) - { - if (Meshes.TryGetValue(newMeshKey, out retMesh)) - { - // The mesh has already been created. Return a new reference to same. - retMesh.IncrementReference(); - } - else - { - retMesh = new BSShapeMesh(new BulletShape()); - // An instance of this mesh has not been created. Build and remember same. - BulletShape newShape = retMesh.CreatePhysicalMesh(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); - - // Check to see if mesh was created (might require an asset). - newShape = VerifyMeshCreated(physicsScene, newShape, prim); - if (!newShape.isNativeShape || prim.AssetFailed() ) - { - // If a mesh was what was created, remember the built shape for later sharing. - // Also note that if meshing failed we put it in the mesh list as there is nothing else to do about the mesh. - Meshes.Add(newMeshKey, retMesh); - } - - retMesh.physShapeInfo = newShape; - } - } - physicsScene.DetailLog("{0},BSShapeMesh,getReference,mesh={1},size={2},lod={3}", prim.LocalID, retMesh, prim.Size, lod); - return retMesh; - } - public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) - { - BSShape ret = null; - // If the underlying shape is native, the actual shape has not been build (waiting for asset) - // and we must create a copy of the native shape since they are never shared. - if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) - { - // TODO: decide when the native shapes should be freed. Check in Dereference? - ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); - } - else - { - // Another reference to this shape is just counted. + // Calling this reference means we want another handle to an existing compound shape + // (usually linksets) so return this copy. IncrementReference(); - ret = this; + return this; } - return ret; - } - public override void Dereference(BSScene physicsScene) - { - lock (Meshes) + // Dereferencing a compound shape releases the hold on all the child shapes. + public override void Dereference(BSScene physicsScene) { - this.DecrementReference(); - physicsScene.DetailLog("{0},BSShapeMesh.Dereference,shape={1}", BSScene.DetailLogZero, this); - // TODO: schedule aging and destruction of unused meshes. - } - } - // Loop through all the known meshes and return the description based on the physical address. - public static bool TryGetMeshByPtr(BulletShape pShape, out BSShapeMesh outMesh) - { - bool ret = false; - BSShapeMesh foundDesc = null; - lock (Meshes) - { - foreach (BSShapeMesh sm in Meshes.Values) + lock (physShapeInfo) { - if (sm.physShapeInfo.ReferenceSame(pShape)) + this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this); + if (referenceCount <= 0) { - foundDesc = sm; - ret = true; - break; - } - - } - } - outMesh = foundDesc; - return ret; - } - - public delegate BulletShape CreateShapeCall(BulletWorld world, int indicesCount, int[] indices, int verticesCount, float[] vertices ); - private BulletShape CreatePhysicalMesh(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, - PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) - { - return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, - (w, iC, i, vC, v) => - { - shapeInfo.Vertices = vC; - return physicsScene.PE.CreateMeshShape(w, iC, i, vC, v); - }); - } - - // Code that uses the mesher to create the index/vertices info for a trimesh shape. - // This is used by the passed 'makeShape' call to create the Bullet mesh shape. - // The actual build call is passed so this logic can be used by several of the shapes that use a - // simple mesh as their base shape. - public static BulletShape CreatePhysicalMeshShape(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, - PrimitiveBaseShape pbs, OMV.Vector3 size, float lod, CreateShapeCall makeShape) - { - BulletShape newShape = new BulletShape(); - - IMesh meshData = null; - lock (physicsScene.mesher) - { - meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, - false, // say it is not physical so a bounding box is not built - false, // do not cache the mesh and do not use previously built versions - false, - false - ); - } - - if (meshData != null) - { - if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) - { - // Release the fetched asset data once it has been used. - pbs.SculptData = Array.Empty(); - prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; - } - - int[] indices = meshData.getIndexListAsInt(); - int realIndicesIndex = indices.Length; - float[] verticesAsFloats = meshData.getVertexListAsFloat(); - - if (BSParam.ShouldRemoveZeroWidthTriangles) - { - // Remove degenerate triangles. These are triangles with two of the vertices - // are the same. This is complicated by the problem that vertices are not - // made unique in sculpties so we have to compare the values in the vertex. - realIndicesIndex = 0; - for (int tri = 0; tri < indices.Length; tri += 3) - { - // Compute displacements into vertex array for each vertex of the triangle - int v1 = indices[tri + 0] * 3; - int v2 = indices[tri + 1] * 3; - int v3 = indices[tri + 2] * 3; - // Check to see if any two of the vertices are the same - if (!( ( verticesAsFloats[v1 + 0] == verticesAsFloats[v2 + 0] - && verticesAsFloats[v1 + 1] == verticesAsFloats[v2 + 1] - && verticesAsFloats[v1 + 2] == verticesAsFloats[v2 + 2]) - || ( verticesAsFloats[v2 + 0] == verticesAsFloats[v3 + 0] - && verticesAsFloats[v2 + 1] == verticesAsFloats[v3 + 1] - && verticesAsFloats[v2 + 2] == verticesAsFloats[v3 + 2]) - || ( verticesAsFloats[v1 + 0] == verticesAsFloats[v3 + 0] - && verticesAsFloats[v1 + 1] == verticesAsFloats[v3 + 1] - && verticesAsFloats[v1 + 2] == verticesAsFloats[v3 + 2]) ) - ) + if (!physicsScene.PE.IsCompound(physShapeInfo)) { - // None of the vertices of the triangles are the same. This is a good triangle; - indices[realIndicesIndex + 0] = indices[tri + 0]; - indices[realIndicesIndex + 1] = indices[tri + 1]; - indices[realIndicesIndex + 2] = indices[tri + 2]; - realIndicesIndex += 3; + // Failed the sanity check!! + physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", + LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString); + physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", + BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString); + return; } + + int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo); + physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", + BSScene.DetailLogZero, physShapeInfo, numChildren); + + // Loop through all the children dereferencing each. + for (int ii = numChildren - 1; ii >= 0; ii--) + { + BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii); + DereferenceAnonCollisionShape(physicsScene, childShape); + } + + lock (CompoundShapes) + CompoundShapes.Remove(physShapeInfo.AddrString); + physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); } } - physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,key={1},origTri={2},realTri={3},numVerts={4}", - BSScene.DetailLogZero, newMeshKey.ToString("X"), indices.Length / 3, realIndicesIndex / 3, verticesAsFloats.Length / 3); - - if (realIndicesIndex != 0) + } + public static bool TryGetCompoundByPtr(BulletShape pShape, out BSShapeCompound outCompound) + { + lock (CompoundShapes) { - newShape = makeShape(physicsScene.World, realIndicesIndex, indices, verticesAsFloats.Length / 3, verticesAsFloats); + string addr = pShape.AddrString; + return CompoundShapes.TryGetValue(addr, out outCompound); + } + } + private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene) + { + BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false); + return cShape; + } + // Sometimes we have a pointer to a collision shape but don't know what type it is. + // Figure out type and call the correct dereference routine. + // Called at taint-time. + private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape) + { + // TODO: figure a better way to go through all the shape types and find a possible instance. + physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,shape={1}", + BSScene.DetailLogZero, pShape); + BSShapeMesh meshDesc; + if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc)) + { + meshDesc.Dereference(physicsScene); + // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundMesh,shape={1}", BSScene.DetailLogZero, pShape); } else { - // Force the asset condition to 'failed' so we won't try to keep fetching and processing this mesh. - prim.PrimAssetState = BSPhysObject.PrimAssetCondition.FailedMeshing; - physicsScene.Logger.DebugFormat("{0} All mesh triangles degenerate. Prim={1}", LogHeader, UsefulPrimInfo(physicsScene, prim) ); - physicsScene.DetailLog("{0},BSShapeMesh.CreatePhysicalMesh,allDegenerate,key={1}", prim.LocalID, newMeshKey); - } - } - newShape.shapeKey = newMeshKey; - - return newShape; - } -} - -// ============================================================================================================ -// BSShapeHull is a physical shape representation htat is made up of many convex hulls. -// The convex hulls are either supplied with the asset or are approximated by one of the -// convex hull creation routines (in OpenSim or in Bullet). -public class BSShapeHull : BSShape -{ -#pragma warning disable 414 - private static string LogHeader = "[BULLETSIM SHAPE HULL]"; -#pragma warning restore 414 - - public static Dictionary Hulls = new Dictionary(); - - - public BSShapeHull(BulletShape pShape) : base(pShape) - { - } - public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) - { - float lod; - System.UInt64 newHullKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - - BSShapeHull retHull = null; - lock (Hulls) - { - if (Hulls.TryGetValue(newHullKey, out retHull)) - { - // The mesh has already been created. Return a new reference to same. - retHull.IncrementReference(); - } - else - { - retHull = new BSShapeHull(new BulletShape()); - // An instance of this mesh has not been created. Build and remember same. - BulletShape newShape = retHull.CreatePhysicalHull(physicsScene, prim, newHullKey, prim.BaseShape, prim.Size, lod); - - // Check to see if hull was created (might require an asset). - newShape = VerifyMeshCreated(physicsScene, newShape, prim); - if (!newShape.isNativeShape || prim.AssetFailed()) + BSShapeHull hullDesc; + if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc)) { - // If a mesh was what was created, remember the built shape for later sharing. - Hulls.Add(newHullKey, retHull); - } - retHull.physShapeInfo = newShape; - } - } - physicsScene.DetailLog("{0},BSShapeHull,getReference,hull={1},size={2},lod={3}", prim.LocalID, retHull, prim.Size, lod); - return retHull; - } - public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) - { - BSShape ret = null; - // If the underlying shape is native, the actual shape has not been build (waiting for asset) - // and we must create a copy of the native shape since they are never shared. - if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) - { - // TODO: decide when the native shapes should be freed. Check in Dereference? - ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); - } - else - { - // Another reference to this shape is just counted. - IncrementReference(); - ret = this; - } - return ret; - } - public override void Dereference(BSScene physicsScene) - { - lock (Hulls) - { - this.DecrementReference(); - physicsScene.DetailLog("{0},BSShapeHull.Dereference,shape={1}", BSScene.DetailLogZero, this); - // TODO: schedule aging and destruction of unused meshes. - } - } - - List m_hulls; - private BulletShape CreatePhysicalHull(BSScene physicsScene, BSPhysObject prim, System.UInt64 newHullKey, - PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) - { - BulletShape newShape = new BulletShape(); - - IMesh meshData = null; - List> allHulls = null; - lock (physicsScene.mesher) - { - // Pass true for physicalness as this prevents the creation of bounding box which is not needed - meshData = physicsScene.mesher.CreateMesh(prim.PhysObjectName, pbs, size, lod, true /* isPhysical */, false /* shouldCache */, false, false); - - // If we should use the asset's hull info, fetch it out of the locked mesher - if (meshData != null && BSParam.ShouldUseAssetHulls) - { - Meshmerizer realMesher = physicsScene.mesher as Meshmerizer; - if (realMesher != null) - { - allHulls = realMesher.GetConvexHulls(size); - } - if (allHulls == null) - { - physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,noAssetHull", prim.LocalID); - } - } - } - - // If there is hull data in the mesh asset, build the hull from that - if (allHulls != null && BSParam.ShouldUseAssetHulls) - { - int hullCount = allHulls.Count; - shapeInfo.HullCount = hullCount; - int totalVertices = 1; // include one for the count of the hulls - // Using the structure described for HACD hulls, create the memory sturcture - // to pass the hull data to the creater. - foreach (List hullVerts in allHulls) - { - totalVertices += 4; // add four for the vertex count and centroid - totalVertices += hullVerts.Count * 3; // one vertex is three dimensions - } - float[] convHulls = new float[totalVertices]; - - convHulls[0] = (float)hullCount; - int jj = 1; - int hullIndex = 0; - foreach (List hullVerts in allHulls) - { - convHulls[jj + 0] = hullVerts.Count; - convHulls[jj + 1] = 0f; // centroid x,y,z - convHulls[jj + 2] = 0f; - convHulls[jj + 3] = 0f; - jj += 4; - foreach (OMV.Vector3 oneVert in hullVerts) - { - convHulls[jj + 0] = oneVert.X; - convHulls[jj + 1] = oneVert.Y; - convHulls[jj + 2] = oneVert.Z; - jj += 3; - } - shapeInfo.SetVerticesPerHull(hullIndex, hullVerts.Count); - hullIndex++; - } - - // create the hull data structure in Bullet - newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); - - physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,assetHulls,hulls={1},totVert={2},shape={3}", - prim.LocalID, hullCount, totalVertices, newShape); - } - - // If no hull specified in the asset and we should use Bullet's HACD approximation... - if (!newShape.HasPhysicalShape && BSParam.ShouldUseBulletHACD) - { - // Build the hull shape from an existing mesh shape. - // The mesh should have already been created in Bullet. - physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,entry", prim.LocalID); - BSShape meshShape = BSShapeMesh.GetReference(physicsScene, true, prim); - - if (meshShape.physShapeInfo.HasPhysicalShape) - { - HACDParams parms = new HACDParams(); - parms.maxVerticesPerHull = BSParam.BHullMaxVerticesPerHull; - parms.minClusters = BSParam.BHullMinClusters; - parms.compacityWeight = BSParam.BHullCompacityWeight; - parms.volumeWeight = BSParam.BHullVolumeWeight; - parms.concavity = BSParam.BHullConcavity; - parms.addExtraDistPoints = BSParam.NumericBool(BSParam.BHullAddExtraDistPoints); - parms.addNeighboursDistPoints = BSParam.NumericBool(BSParam.BHullAddNeighboursDistPoints); - parms.addFacesPoints = BSParam.NumericBool(BSParam.BHullAddFacesPoints); - parms.shouldAdjustCollisionMargin = BSParam.NumericBool(BSParam.BHullShouldAdjustCollisionMargin); - parms.whichHACD = 0; // Use the HACD routine that comes with Bullet - - physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,beforeCall", prim.LocalID, newShape.HasPhysicalShape); - newShape = physicsScene.PE.BuildHullShapeFromMesh(physicsScene.World, meshShape.physShapeInfo, parms); - physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,hullFromMesh,shape={1}", prim.LocalID, newShape); - - // Now done with the mesh shape. - shapeInfo.HullCount = 1; - BSShapeMesh maybeMesh = meshShape as BSShapeMesh; - if (maybeMesh != null) - shapeInfo.SetVerticesPerHull(0, maybeMesh.shapeInfo.Vertices); - meshShape.Dereference(physicsScene); - } - physicsScene.DetailLog("{0},BSShapeHull.CreatePhysicalHull,bulletHACD,exit,hasBody={1}", prim.LocalID, newShape.HasPhysicalShape); - } - - // If no other hull specifications, use our HACD hull approximation. - if (!newShape.HasPhysicalShape && meshData != null) - { - if (prim.PrimAssetState == BSPhysObject.PrimAssetCondition.Fetched) - { - // Release the fetched asset data once it has been used. - pbs.SculptData = Array.Empty(); - prim.PrimAssetState = BSPhysObject.PrimAssetCondition.Unknown; - } - - int[] indices = meshData.getIndexListAsInt(); - List vertices = meshData.getVertexList(); - - //format conversion from IMesh format to DecompDesc format - List convIndices = new List(); - List convVertices = new List(); - for (int ii = 0; ii < indices.GetLength(0); ii++) - { - convIndices.Add(indices[ii]); - } - foreach (OMV.Vector3 vv in vertices) - { - convVertices.Add(new float3(vv.X, vv.Y, vv.Z)); - } - - uint maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplit; - if (BSParam.CSHullMaxDepthSplit != BSParam.CSHullMaxDepthSplitForSimpleShapes) - { - // Simple primitive shapes we know are convex so they are better implemented with - // fewer hulls. - // Check for simple shape (prim without cuts) and reduce split parameter if so. - if (BSShapeCollection.PrimHasNoCuts(pbs)) - { - maxDepthSplit = (uint)BSParam.CSHullMaxDepthSplitForSimpleShapes; - } - } - - // setup and do convex hull conversion - m_hulls = new List(); - DecompDesc dcomp = new DecompDesc(); - dcomp.mIndices = convIndices; - dcomp.mVertices = convVertices; - dcomp.mDepth = maxDepthSplit; - dcomp.mCpercent = BSParam.CSHullConcavityThresholdPercent; - dcomp.mPpercent = BSParam.CSHullVolumeConservationThresholdPercent; - dcomp.mMaxVertices = (uint)BSParam.CSHullMaxVertices; - dcomp.mSkinWidth = BSParam.CSHullMaxSkinWidth; - ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn); - // create the hull into the _hulls variable - convexBuilder.process(dcomp); - - physicsScene.DetailLog("{0},BSShapeCollection.CreatePhysicalHull,key={1},inVert={2},inInd={3},split={4},hulls={5}", - BSScene.DetailLogZero, newHullKey, indices.GetLength(0), vertices.Count, maxDepthSplit, m_hulls.Count); - - // Convert the vertices and indices for passing to unmanaged. - // The hull information is passed as a large floating point array. - // The format is: - // convHulls[0] = number of hulls - // convHulls[1] = number of vertices in first hull - // convHulls[2] = hull centroid X coordinate - // convHulls[3] = hull centroid Y coordinate - // convHulls[4] = hull centroid Z coordinate - // convHulls[5] = first hull vertex X - // convHulls[6] = first hull vertex Y - // convHulls[7] = first hull vertex Z - // convHulls[8] = second hull vertex X - // ... - // convHulls[n] = number of vertices in second hull - // convHulls[n+1] = second hull centroid X coordinate - // ... - // - // TODO: is is very inefficient. Someday change the convex hull generator to return - // data structures that do not need to be converted in order to pass to Bullet. - // And maybe put the values directly into pinned memory rather than marshaling. - int hullCount = m_hulls.Count; - int totalVertices = 1; // include one for the count of the hulls - foreach (ConvexResult cr in m_hulls) - { - totalVertices += 4; // add four for the vertex count and centroid - totalVertices += cr.HullIndices.Count * 3; // we pass just triangles - } - float[] convHulls = new float[totalVertices]; - - convHulls[0] = (float)hullCount; - int jj = 1; - foreach (ConvexResult cr in m_hulls) - { - // copy vertices for index access - float3[] verts = new float3[cr.HullVertices.Count]; - int kk = 0; - foreach (float3 ff in cr.HullVertices) - { - verts[kk++] = ff; - } - - // add to the array one hull's worth of data - convHulls[jj++] = cr.HullIndices.Count; - convHulls[jj++] = 0f; // centroid x,y,z - convHulls[jj++] = 0f; - convHulls[jj++] = 0f; - foreach (int ind in cr.HullIndices) - { - convHulls[jj++] = verts[ind].x; - convHulls[jj++] = verts[ind].y; - convHulls[jj++] = verts[ind].z; - } - } - // create the hull data structure in Bullet - newShape = physicsScene.PE.CreateHullShape(physicsScene.World, hullCount, convHulls); - } - newShape.shapeKey = newHullKey; - return newShape; - } - // Callback from convex hull creater with a newly created hull. - // Just add it to our collection of hulls for this shape. - private void HullReturn(ConvexResult result) - { - m_hulls.Add(result); - return; - } - // Loop through all the known hulls and return the description based on the physical address. - public static bool TryGetHullByPtr(BulletShape pShape, out BSShapeHull outHull) - { - bool ret = false; - BSShapeHull foundDesc = null; - lock (Hulls) - { - foreach (BSShapeHull sh in Hulls.Values) - { - if (sh.physShapeInfo.ReferenceSame(pShape)) - { - foundDesc = sh; - ret = true; - break; - } - - } - } - outHull = foundDesc; - return ret; - } -} - -// ============================================================================================================ -// BSShapeCompound is a wrapper for the Bullet compound shape which is built from multiple, separate -// meshes. Used by BulletSim for complex shapes like linksets. -public class BSShapeCompound : BSShape -{ - private static string LogHeader = "[BULLETSIM SHAPE COMPOUND]"; - public static Dictionary CompoundShapes = new Dictionary(); - - public BSShapeCompound(BulletShape pShape) : base(pShape) - { - } - public static BSShape GetReference(BSScene physicsScene) - { - // Base compound shapes are not shared so this returns a raw shape. - // A built compound shape can be reused in linksets. - BSShapeCompound ret = new BSShapeCompound(CreatePhysicalCompoundShape(physicsScene)); - CompoundShapes.Add(ret.AddrString, ret); - return ret; - } - public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) - { - // Calling this reference means we want another handle to an existing compound shape - // (usually linksets) so return this copy. - IncrementReference(); - return this; - } - // Dereferencing a compound shape releases the hold on all the child shapes. - public override void Dereference(BSScene physicsScene) - { - lock (physShapeInfo) - { - this.DecrementReference(); - physicsScene.DetailLog("{0},BSShapeCompound.Dereference,shape={1}", BSScene.DetailLogZero, this); - if (referenceCount <= 0) - { - if (!physicsScene.PE.IsCompound(physShapeInfo)) - { - // Failed the sanity check!! - physicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", - LogHeader, physShapeInfo.shapeType, physShapeInfo.AddrString); - physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", - BSScene.DetailLogZero, physShapeInfo.shapeType, physShapeInfo.AddrString); - return; - } - - int numChildren = physicsScene.PE.GetNumberOfCompoundChildren(physShapeInfo); - physicsScene.DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", - BSScene.DetailLogZero, physShapeInfo, numChildren); - - // Loop through all the children dereferencing each. - for (int ii = numChildren - 1; ii >= 0; ii--) - { - BulletShape childShape = physicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(physShapeInfo, ii); - DereferenceAnonCollisionShape(physicsScene, childShape); - } - - lock (CompoundShapes) - CompoundShapes.Remove(physShapeInfo.AddrString); - physicsScene.PE.DeleteCollisionShape(physicsScene.World, physShapeInfo); - } - } - } - public static bool TryGetCompoundByPtr(BulletShape pShape, out BSShapeCompound outCompound) - { - lock (CompoundShapes) - { - string addr = pShape.AddrString; - return CompoundShapes.TryGetValue(addr, out outCompound); - } - } - private static BulletShape CreatePhysicalCompoundShape(BSScene physicsScene) - { - BulletShape cShape = physicsScene.PE.CreateCompoundShape(physicsScene.World, false); - return cShape; - } - // Sometimes we have a pointer to a collision shape but don't know what type it is. - // Figure out type and call the correct dereference routine. - // Called at taint-time. - private void DereferenceAnonCollisionShape(BSScene physicsScene, BulletShape pShape) - { - // TODO: figure a better way to go through all the shape types and find a possible instance. - physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,shape={1}", - BSScene.DetailLogZero, pShape); - BSShapeMesh meshDesc; - if (BSShapeMesh.TryGetMeshByPtr(pShape, out meshDesc)) - { - meshDesc.Dereference(physicsScene); - // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundMesh,shape={1}", BSScene.DetailLogZero, pShape); - } - else - { - BSShapeHull hullDesc; - if (BSShapeHull.TryGetHullByPtr(pShape, out hullDesc)) - { - hullDesc.Dereference(physicsScene); - // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundHull,shape={1}", BSScene.DetailLogZero, pShape); - } - else - { - BSShapeConvexHull chullDesc; - if (BSShapeConvexHull.TryGetConvexHullByPtr(pShape, out chullDesc)) - { - chullDesc.Dereference(physicsScene); - // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundConvexHull,shape={1}", BSScene.DetailLogZero, pShape); + hullDesc.Dereference(physicsScene); + // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundHull,shape={1}", BSScene.DetailLogZero, pShape); } else { - BSShapeGImpact gImpactDesc; - if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc)) + BSShapeConvexHull chullDesc; + if (BSShapeConvexHull.TryGetConvexHullByPtr(pShape, out chullDesc)) { - gImpactDesc.Dereference(physicsScene); - // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundgImpact,shape={1}", BSScene.DetailLogZero, pShape); + chullDesc.Dereference(physicsScene); + // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundConvexHull,shape={1}", BSScene.DetailLogZero, pShape); } else { - // Didn't find it in the lists of specific types. It could be compound. - BSShapeCompound compoundDesc; - if (BSShapeCompound.TryGetCompoundByPtr(pShape, out compoundDesc)) + BSShapeGImpact gImpactDesc; + if (BSShapeGImpact.TryGetGImpactByPtr(pShape, out gImpactDesc)) { - compoundDesc.Dereference(physicsScene); - // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,recursiveCompoundShape,shape={1}", BSScene.DetailLogZero, pShape); + gImpactDesc.Dereference(physicsScene); + // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,foundgImpact,shape={1}", BSScene.DetailLogZero, pShape); } else { - // If none of the above, maybe it is a simple native shape. - if (physicsScene.PE.IsNativeShape(pShape)) + // Didn't find it in the lists of specific types. It could be compound. + BSShapeCompound compoundDesc; + if (BSShapeCompound.TryGetCompoundByPtr(pShape, out compoundDesc)) { - // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,assumingNative,shape={1}", BSScene.DetailLogZero, pShape); - BSShapeNative nativeShape = new BSShapeNative(pShape); - nativeShape.Dereference(physicsScene); + compoundDesc.Dereference(physicsScene); + // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,recursiveCompoundShape,shape={1}", BSScene.DetailLogZero, pShape); } else { - physicsScene.Logger.WarnFormat("{0} DereferenceAnonCollisionShape. Did not find shape. {1}", - LogHeader, pShape); + // If none of the above, maybe it is a simple native shape. + if (physicsScene.PE.IsNativeShape(pShape)) + { + // physicsScene.DetailLog("{0},BSShapeCompound.DereferenceAnonCollisionShape,assumingNative,shape={1}", BSScene.DetailLogZero, pShape); + BSShapeNative nativeShape = new BSShapeNative(pShape); + nativeShape.Dereference(physicsScene); + } + else + { + physicsScene.Logger.WarnFormat("{0} DereferenceAnonCollisionShape. Did not find shape. {1}", + LogHeader, pShape); + } } } } @@ -1095,371 +1096,369 @@ public class BSShapeCompound : BSShape } } } -} -// ============================================================================================================ -// BSShapeConvexHull is a wrapper for a Bullet single convex hull. A BSShapeHull contains multiple convex -// hull shapes. This is used for simple prims that are convex and thus can be made into a simple -// collision shape (a single hull). More complex physical shapes will be BSShapeHull's. -public class BSShapeConvexHull : BSShape -{ -#pragma warning disable 414 - private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]"; -#pragma warning restore 414 - - public static Dictionary ConvexHulls = new Dictionary(); - - public BSShapeConvexHull(BulletShape pShape) : base(pShape) + // ============================================================================================================ + // BSShapeConvexHull is a wrapper for a Bullet single convex hull. A BSShapeHull contains multiple convex + // hull shapes. This is used for simple prims that are convex and thus can be made into a simple + // collision shape (a single hull). More complex physical shapes will be BSShapeHull's. + public class BSShapeConvexHull : BSShape { - } - public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) - { - float lod; - System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + #pragma warning disable 414 + private static string LogHeader = "[BULLETSIM SHAPE CONVEX HULL]"; + #pragma warning restore 414 - physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}", - prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); + public static Dictionary ConvexHulls = new Dictionary(); - BSShapeConvexHull retConvexHull = null; - lock (ConvexHulls) + public BSShapeConvexHull(BulletShape pShape) : base(pShape) { - if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull)) - { - // The mesh has already been created. Return a new reference to same. - retConvexHull.IncrementReference(); - } - else - { - retConvexHull = new BSShapeConvexHull(new BulletShape()); - BulletShape convexShape = null; + } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + float lod; + System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); - // Get a handle to a mesh to build the hull from - BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim); - if (baseMesh.physShapeInfo.isNativeShape) + physicsScene.DetailLog("{0},BSShapeConvexHull,getReference,newKey={1},size={2},lod={3}", + prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); + + BSShapeConvexHull retConvexHull = null; + lock (ConvexHulls) + { + if (ConvexHulls.TryGetValue(newMeshKey, out retConvexHull)) { - // We get here if the mesh was not creatable. Could be waiting for an asset from the disk. - // In the short term, we return the native shape and a later ForceBodyShapeRebuild should - // get back to this code with a buildable mesh. - // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed? - convexShape = baseMesh.physShapeInfo; + // The mesh has already been created. Return a new reference to same. + retConvexHull.IncrementReference(); } else { - convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo); - convexShape.shapeKey = newMeshKey; - ConvexHulls.Add(convexShape.shapeKey, retConvexHull); - physicsScene.DetailLog("{0},BSShapeConvexHull.GetReference,addingNewlyCreatedShape,shape={1}", - BSScene.DetailLogZero, convexShape); + retConvexHull = new BSShapeConvexHull(new BulletShape()); + BulletShape convexShape = null; + + // Get a handle to a mesh to build the hull from + BSShape baseMesh = BSShapeMesh.GetReference(physicsScene, false /* forceRebuild */, prim); + if (baseMesh.physShapeInfo.isNativeShape) + { + // We get here if the mesh was not creatable. Could be waiting for an asset from the disk. + // In the short term, we return the native shape and a later ForceBodyShapeRebuild should + // get back to this code with a buildable mesh. + // TODO: not sure the temp native shape is freed when the mesh is rebuilt. When does this get freed? + convexShape = baseMesh.physShapeInfo; + } + else + { + convexShape = physicsScene.PE.BuildConvexHullShapeFromMesh(physicsScene.World, baseMesh.physShapeInfo); + convexShape.shapeKey = newMeshKey; + ConvexHulls.Add(convexShape.shapeKey, retConvexHull); + physicsScene.DetailLog("{0},BSShapeConvexHull.GetReference,addingNewlyCreatedShape,shape={1}", + BSScene.DetailLogZero, convexShape); + } + + // Done with the base mesh + baseMesh.Dereference(physicsScene); + + retConvexHull.physShapeInfo = convexShape; } - - // Done with the base mesh - baseMesh.Dereference(physicsScene); - - retConvexHull.physShapeInfo = convexShape; + } + return retConvexHull; + } + public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) + { + // Calling this reference means we want another handle to an existing shape + // (usually linksets) so return this copy. + IncrementReference(); + return this; + } + // Dereferencing a compound shape releases the hold on all the child shapes. + public override void Dereference(BSScene physicsScene) + { + lock (ConvexHulls) + { + this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this); + // TODO: schedule aging and destruction of unused meshes. } } - return retConvexHull; - } - public override BSShape GetReference(BSScene physicsScene, BSPhysObject prim) - { - // Calling this reference means we want another handle to an existing shape - // (usually linksets) so return this copy. - IncrementReference(); - return this; - } - // Dereferencing a compound shape releases the hold on all the child shapes. - public override void Dereference(BSScene physicsScene) - { - lock (ConvexHulls) + // Loop through all the known hulls and return the description based on the physical address. + public static bool TryGetConvexHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull) { - this.DecrementReference(); - physicsScene.DetailLog("{0},BSShapeConvexHull.Dereference,shape={1}", BSScene.DetailLogZero, this); - // TODO: schedule aging and destruction of unused meshes. - } - } - // Loop through all the known hulls and return the description based on the physical address. - public static bool TryGetConvexHullByPtr(BulletShape pShape, out BSShapeConvexHull outHull) - { - bool ret = false; - BSShapeConvexHull foundDesc = null; - lock (ConvexHulls) - { - foreach (BSShapeConvexHull sh in ConvexHulls.Values) + bool ret = false; + BSShapeConvexHull foundDesc = null; + lock (ConvexHulls) { - if (sh.physShapeInfo.ReferenceSame(pShape)) + foreach (BSShapeConvexHull sh in ConvexHulls.Values) { - foundDesc = sh; - ret = true; - break; + if (sh.physShapeInfo.ReferenceSame(pShape)) + { + foundDesc = sh; + ret = true; + break; + } + } - } + outHull = foundDesc; + return ret; } - outHull = foundDesc; - return ret; } -} -// ============================================================================================================ -// BSShapeGImpact is a wrapper for the Bullet GImpact shape which is a collision mesh shape that -// can handle concave as well as convex shapes. Much slower computationally but creates smoother -// shapes than multiple convex hull approximations. -public class BSShapeGImpact : BSShape -{ -#pragma warning disable 414 - private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]"; -#pragma warning restore 414 - - public static Dictionary GImpacts = new Dictionary(); - - public BSShapeGImpact(BulletShape pShape) : base(pShape) + // ============================================================================================================ + // BSShapeGImpact is a wrapper for the Bullet GImpact shape which is a collision mesh shape that + // can handle concave as well as convex shapes. Much slower computationally but creates smoother + // shapes than multiple convex hull approximations. + public class BSShapeGImpact : BSShape { - } - public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) - { - float lod; - System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + #pragma warning disable 414 + private static string LogHeader = "[BULLETSIM SHAPE GIMPACT]"; + #pragma warning restore 414 - physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}", - prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); + public static Dictionary GImpacts = new Dictionary(); - BSShapeGImpact retGImpact = null; - lock (GImpacts) + public BSShapeGImpact(BulletShape pShape) : base(pShape) { - if (GImpacts.TryGetValue(newMeshKey, out retGImpact)) + } + public static BSShape GetReference(BSScene physicsScene, bool forceRebuild, BSPhysObject prim) + { + float lod; + System.UInt64 newMeshKey = BSShape.ComputeShapeKey(prim.Size, prim.BaseShape, out lod); + + physicsScene.DetailLog("{0},BSShapeGImpact,getReference,newKey={1},size={2},lod={3}", + prim.LocalID, newMeshKey.ToString("X"), prim.Size, lod); + + BSShapeGImpact retGImpact = null; + lock (GImpacts) { - // The mesh has already been created. Return a new reference to same. - retGImpact.IncrementReference(); + if (GImpacts.TryGetValue(newMeshKey, out retGImpact)) + { + // The mesh has already been created. Return a new reference to same. + retGImpact.IncrementReference(); + } + else + { + retGImpact = new BSShapeGImpact(new BulletShape()); + BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); + + // Check to see if mesh was created (might require an asset). + newShape = VerifyMeshCreated(physicsScene, newShape, prim); + newShape.shapeKey = newMeshKey; + if (!newShape.isNativeShape || prim.AssetFailed()) + { + // If a mesh was what was created, remember the built shape for later sharing. + // Also note that if meshing failed we put it in the mesh list as there is nothing + // else to do about the mesh. + GImpacts.Add(newMeshKey, retGImpact); + } + + retGImpact.physShapeInfo = newShape; + } + } + return retGImpact; + } + + private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, + PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) + { + return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, + (w, iC, i, vC, v) => + { + shapeInfo.Vertices = vC; + return physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v); + }); + } + + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) + { + BSShape ret = null; + // If the underlying shape is native, the actual shape has not been build (waiting for asset) + // and we must create a copy of the native shape since they are never shared. + if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) + { + // TODO: decide when the native shapes should be freed. Check in Dereference? + ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); } else { - retGImpact = new BSShapeGImpact(new BulletShape()); - BulletShape newShape = retGImpact.CreatePhysicalGImpact(physicsScene, prim, newMeshKey, prim.BaseShape, prim.Size, lod); - - // Check to see if mesh was created (might require an asset). - newShape = VerifyMeshCreated(physicsScene, newShape, prim); - newShape.shapeKey = newMeshKey; - if (!newShape.isNativeShape || prim.AssetFailed()) - { - // If a mesh was what was created, remember the built shape for later sharing. - // Also note that if meshing failed we put it in the mesh list as there is nothing - // else to do about the mesh. - GImpacts.Add(newMeshKey, retGImpact); - } - - retGImpact.physShapeInfo = newShape; + // Another reference to this shape is just counted. + IncrementReference(); + ret = this; } + return ret; } - return retGImpact; - } - - private BulletShape CreatePhysicalGImpact(BSScene physicsScene, BSPhysObject prim, System.UInt64 newMeshKey, - PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) - { - return BSShapeMesh.CreatePhysicalMeshShape(physicsScene, prim, newMeshKey, pbs, size, lod, - (w, iC, i, vC, v) => - { - shapeInfo.Vertices = vC; - return physicsScene.PE.CreateGImpactShape(w, iC, i, vC, v); - }); - } - - public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) - { - BSShape ret = null; - // If the underlying shape is native, the actual shape has not been build (waiting for asset) - // and we must create a copy of the native shape since they are never shared. - if (physShapeInfo.HasPhysicalShape && physShapeInfo.isNativeShape) + // Dereferencing a compound shape releases the hold on all the child shapes. + public override void Dereference(BSScene physicsScene) { - // TODO: decide when the native shapes should be freed. Check in Dereference? - ret = BSShapeNative.GetReference(pPhysicsScene, pPrim, BSPhysicsShapeType.SHAPE_BOX, FixedShapeKey.KEY_BOX); - } - else - { - // Another reference to this shape is just counted. - IncrementReference(); - ret = this; - } - return ret; - } - // Dereferencing a compound shape releases the hold on all the child shapes. - public override void Dereference(BSScene physicsScene) - { - lock (GImpacts) - { - this.DecrementReference(); - physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this); - // TODO: schedule aging and destruction of unused meshes. - } - } - // Loop through all the known hulls and return the description based on the physical address. - public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull) - { - bool ret = false; - BSShapeGImpact foundDesc = null; - lock (GImpacts) - { - foreach (BSShapeGImpact sh in GImpacts.Values) + lock (GImpacts) { - if (sh.physShapeInfo.ReferenceSame(pShape)) - { - foundDesc = sh; - ret = true; - break; - } - + this.DecrementReference(); + physicsScene.DetailLog("{0},BSShapeGImpact.Dereference,shape={1}", BSScene.DetailLogZero, this); + // TODO: schedule aging and destruction of unused meshes. } } - outHull = foundDesc; - return ret; + // Loop through all the known hulls and return the description based on the physical address. + public static bool TryGetGImpactByPtr(BulletShape pShape, out BSShapeGImpact outHull) + { + bool ret = false; + BSShapeGImpact foundDesc = null; + lock (GImpacts) + { + foreach (BSShapeGImpact sh in GImpacts.Values) + { + if (sh.physShapeInfo.ReferenceSame(pShape)) + { + foundDesc = sh; + ret = true; + break; + } + + } + } + outHull = foundDesc; + return ret; + } + } + + // ============================================================================================================ + // BSShapeAvatar is a specialized mesh shape for avatars. + public class BSShapeAvatar : BSShape + { + #pragma warning disable 414 + private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; + #pragma warning restore 414 + + public BSShapeAvatar() + : base() + { + } + public static BSShape GetReference(BSPhysObject prim) + { + return new BSShapeNull(); + } + public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) + { + return new BSShapeNull(); + } + public override void Dereference(BSScene physicsScene) { } + + // From the front: + // A---A + // / \ + // B-------B + // / \ +Z + // C-----------C | + // \ / -Y --+-- +Y + // \ / | + // \ / -Z + // D-----D + // \ / + // E-E + + // From the top A and E are just lines. + // B, C and D are hexagons: + // + // C1--C2 +X + // / \ | + // C0 C3 -Y --+-- +Y + // \ / | + // C5--C4 -X + + // Zero goes directly through the middle so the offsets are from that middle axis + // and up and down from a middle horizon (A and E are the same distance from the zero). + // The height, width and depth is one. All scaling is done by the simulator. + + // Z component -- how far the level is from the middle zero + private const float Aup = 0.5f; + private const float Bup = 0.4f; + private const float Cup = 0.3f; + private const float Dup = -0.4f; + private const float Eup = -0.5f; + + // Y component -- distance from center to x0 and x3 + private const float Awid = 0.25f; + private const float Bwid = 0.3f; + private const float Cwid = 0.5f; + private const float Dwid = 0.3f; + private const float Ewid = 0.2f; + + // Y component -- distance from center to x1, x2, x4 and x5 + private const float Afwid = 0.0f; + private const float Bfwid = 0.2f; + private const float Cfwid = 0.4f; + private const float Dfwid = 0.2f; + private const float Efwid = 0.0f; + + // X component -- distance from zero to the front or back of a level + private const float Adep = 0f; + private const float Bdep = 0.3f; + private const float Cdep = 0.5f; + private const float Ddep = 0.2f; + private const float Edep = 0f; + + private OMV.Vector3[] avatarVertices = { + new OMV.Vector3( 0.0f, -Awid, Aup), // A0 + new OMV.Vector3( 0.0f, +Awid, Aup), // A3 + + new OMV.Vector3( 0.0f, -Bwid, Bup), // B0 + new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1 + new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2 + new OMV.Vector3( 0.0f, +Bwid, Bup), // B3 + new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4 + new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5 + + new OMV.Vector3( 0.0f, -Cwid, Cup), // C0 + new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1 + new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2 + new OMV.Vector3( 0.0f, +Cwid, Cup), // C3 + new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4 + new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5 + + new OMV.Vector3( 0.0f, -Dwid, Dup), // D0 + new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1 + new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2 + new OMV.Vector3( 0.0f, +Dwid, Dup), // D3 + new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4 + new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5 + + new OMV.Vector3( 0.0f, -Ewid, Eup), // E0 + new OMV.Vector3( 0.0f, +Ewid, Eup), // E3 + }; + + // Offsets of the vertices in the vertices array + private enum Ind : int + { + A0, A3, + B0, B1, B2, B3, B4, B5, + C0, C1, C2, C3, C4, C5, + D0, D1, D2, D3, D4, D5, + E0, E3 + } + + // Comments specify trianges and quads in clockwise direction + private Ind[] avatarIndices = { + Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1 + Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3 + Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3 + Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4 + Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0 + Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0 + + Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1 + Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2 + Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3 + Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4 + Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5 + Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0 + + Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1 + Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2 + Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3 + Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4 + Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5 + Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0 + + Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1 + Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3 + Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3 + Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4 + Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0 + Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0 + + }; } } - -// ============================================================================================================ -// BSShapeAvatar is a specialized mesh shape for avatars. -public class BSShapeAvatar : BSShape -{ -#pragma warning disable 414 - private static string LogHeader = "[BULLETSIM SHAPE AVATAR]"; -#pragma warning restore 414 - - public BSShapeAvatar() - : base() - { - } - public static BSShape GetReference(BSPhysObject prim) - { - return new BSShapeNull(); - } - public override BSShape GetReference(BSScene pPhysicsScene, BSPhysObject pPrim) - { - return new BSShapeNull(); - } - public override void Dereference(BSScene physicsScene) { } - - // From the front: - // A---A - // / \ - // B-------B - // / \ +Z - // C-----------C | - // \ / -Y --+-- +Y - // \ / | - // \ / -Z - // D-----D - // \ / - // E-E - - // From the top A and E are just lines. - // B, C and D are hexagons: - // - // C1--C2 +X - // / \ | - // C0 C3 -Y --+-- +Y - // \ / | - // C5--C4 -X - - // Zero goes directly through the middle so the offsets are from that middle axis - // and up and down from a middle horizon (A and E are the same distance from the zero). - // The height, width and depth is one. All scaling is done by the simulator. - - // Z component -- how far the level is from the middle zero - private const float Aup = 0.5f; - private const float Bup = 0.4f; - private const float Cup = 0.3f; - private const float Dup = -0.4f; - private const float Eup = -0.5f; - - // Y component -- distance from center to x0 and x3 - private const float Awid = 0.25f; - private const float Bwid = 0.3f; - private const float Cwid = 0.5f; - private const float Dwid = 0.3f; - private const float Ewid = 0.2f; - - // Y component -- distance from center to x1, x2, x4 and x5 - private const float Afwid = 0.0f; - private const float Bfwid = 0.2f; - private const float Cfwid = 0.4f; - private const float Dfwid = 0.2f; - private const float Efwid = 0.0f; - - // X component -- distance from zero to the front or back of a level - private const float Adep = 0f; - private const float Bdep = 0.3f; - private const float Cdep = 0.5f; - private const float Ddep = 0.2f; - private const float Edep = 0f; - - private OMV.Vector3[] avatarVertices = { - new OMV.Vector3( 0.0f, -Awid, Aup), // A0 - new OMV.Vector3( 0.0f, +Awid, Aup), // A3 - - new OMV.Vector3( 0.0f, -Bwid, Bup), // B0 - new OMV.Vector3(+Bdep, -Bfwid, Bup), // B1 - new OMV.Vector3(+Bdep, +Bfwid, Bup), // B2 - new OMV.Vector3( 0.0f, +Bwid, Bup), // B3 - new OMV.Vector3(-Bdep, +Bfwid, Bup), // B4 - new OMV.Vector3(-Bdep, -Bfwid, Bup), // B5 - - new OMV.Vector3( 0.0f, -Cwid, Cup), // C0 - new OMV.Vector3(+Cdep, -Cfwid, Cup), // C1 - new OMV.Vector3(+Cdep, +Cfwid, Cup), // C2 - new OMV.Vector3( 0.0f, +Cwid, Cup), // C3 - new OMV.Vector3(-Cdep, +Cfwid, Cup), // C4 - new OMV.Vector3(-Cdep, -Cfwid, Cup), // C5 - - new OMV.Vector3( 0.0f, -Dwid, Dup), // D0 - new OMV.Vector3(+Ddep, -Dfwid, Dup), // D1 - new OMV.Vector3(+Ddep, +Dfwid, Dup), // D2 - new OMV.Vector3( 0.0f, +Dwid, Dup), // D3 - new OMV.Vector3(-Ddep, +Dfwid, Dup), // D4 - new OMV.Vector3(-Ddep, -Dfwid, Dup), // D5 - - new OMV.Vector3( 0.0f, -Ewid, Eup), // E0 - new OMV.Vector3( 0.0f, +Ewid, Eup), // E3 - }; - - // Offsets of the vertices in the vertices array - private enum Ind : int - { - A0, A3, - B0, B1, B2, B3, B4, B5, - C0, C1, C2, C3, C4, C5, - D0, D1, D2, D3, D4, D5, - E0, E3 - } - - // Comments specify trianges and quads in clockwise direction - private Ind[] avatarIndices = { - Ind.A0, Ind.B0, Ind.B1, // A0,B0,B1 - Ind.A0, Ind.B1, Ind.B2, Ind.B2, Ind.A3, Ind.A0, // A0,B1,B2,A3 - Ind.A3, Ind.B2, Ind.B3, // A3,B2,B3 - Ind.A3, Ind.B3, Ind.B4, // A3,B3,B4 - Ind.A3, Ind.B4, Ind.B5, Ind.B5, Ind.A0, Ind.A3, // A3,B4,B5,A0 - Ind.A0, Ind.B5, Ind.B0, // A0,B5,B0 - - Ind.B0, Ind.C0, Ind.C1, Ind.C1, Ind.B1, Ind.B0, // B0,C0,C1,B1 - Ind.B1, Ind.C1, Ind.C2, Ind.C2, Ind.B2, Ind.B1, // B1,C1,C2,B2 - Ind.B2, Ind.C2, Ind.C3, Ind.C3, Ind.B3, Ind.B2, // B2,C2,C3,B3 - Ind.B3, Ind.C3, Ind.C4, Ind.C4, Ind.B4, Ind.B3, // B3,C3,C4,B4 - Ind.B4, Ind.C4, Ind.C5, Ind.C5, Ind.B5, Ind.B4, // B4,C4,C5,B5 - Ind.B5, Ind.C5, Ind.C0, Ind.C0, Ind.B0, Ind.B5, // B5,C5,C0,B0 - - Ind.C0, Ind.D0, Ind.D1, Ind.D1, Ind.C1, Ind.C0, // C0,D0,D1,C1 - Ind.C1, Ind.D1, Ind.D2, Ind.D2, Ind.C2, Ind.C1, // C1,D1,D2,C2 - Ind.C2, Ind.D2, Ind.D3, Ind.D3, Ind.C3, Ind.C2, // C2,D2,D3,C3 - Ind.C3, Ind.D3, Ind.D4, Ind.D4, Ind.C4, Ind.C3, // C3,D3,D4,C4 - Ind.C4, Ind.D4, Ind.D5, Ind.D5, Ind.C5, Ind.C4, // C4,D4,D5,C5 - Ind.C5, Ind.D5, Ind.D0, Ind.D0, Ind.C0, Ind.C5, // C5,D5,D0,C0 - - Ind.E0, Ind.D0, Ind.D1, // E0,D0,D1 - Ind.E0, Ind.D1, Ind.D2, Ind.D2, Ind.E3, Ind.E0, // E0,D1,D2,E3 - Ind.E3, Ind.D2, Ind.D3, // E3,D2,D3 - Ind.E3, Ind.D3, Ind.D4, // E3,D3,D4 - Ind.E3, Ind.D4, Ind.D5, Ind.D5, Ind.E0, Ind.E3, // E3,D4,D5,E0 - Ind.E0, Ind.D5, Ind.D0, // E0,D5,D0 - - }; - -} -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs index 1cb948e802..80584b07d1 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainHeightmap.cs @@ -39,148 +39,148 @@ using OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -public sealed class BSTerrainHeightmap : BSTerrainPhys -{ - static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; - - BulletHMapInfo m_mapInfo = null; - - // Constructor to build a default, flat heightmap terrain. - public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) - : base(physicsScene, regionBase, id) + public sealed class BSTerrainHeightmap : BSTerrainPhys { - Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE); - Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION); - int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; - float[] initialMap = new float[totalHeights]; - for (int ii = 0; ii < totalHeights; ii++) + static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; + + BulletHMapInfo m_mapInfo = null; + + // Constructor to build a default, flat heightmap terrain. + public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) + : base(physicsScene, regionBase, id) { - initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; - } - m_mapInfo = new BulletHMapInfo(id, initialMap, regionSize.X, regionSize.Y); - m_mapInfo.minCoords = minTerrainCoords; - m_mapInfo.maxCoords = maxTerrainCoords; - m_mapInfo.terrainRegionBase = TerrainBase; - // Don't have to free any previous since we just got here. - BuildHeightmapTerrain(); - } - - // This minCoords and maxCoords passed in give the size of the terrain (min and max Z - // are the high and low points of the heightmap). - public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, - Vector3 minCoords, Vector3 maxCoords) - : base(physicsScene, regionBase, id) - { - m_mapInfo = new BulletHMapInfo(id, initialMap, maxCoords.X - minCoords.X, maxCoords.Y - minCoords.Y); - m_mapInfo.minCoords = minCoords; - m_mapInfo.maxCoords = maxCoords; - m_mapInfo.minZ = minCoords.Z; - m_mapInfo.maxZ = maxCoords.Z; - m_mapInfo.terrainRegionBase = TerrainBase; - - // Don't have to free any previous since we just got here. - BuildHeightmapTerrain(); - } - - public override void Dispose() - { - ReleaseHeightMapTerrain(); - } - - // Using the information in m_mapInfo, create the physical representation of the heightmap. - private void BuildHeightmapTerrain() - { - // Create the terrain shape from the mapInfo - m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID, - new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, - m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); - - - // The terrain object initial position is at the center of the object - Vector3 centerPos; - centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f); - centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); - centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); - - m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, - m_mapInfo.ID, centerPos, Quaternion.Identity); - - // Set current terrain attributes - m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); - m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); - m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); - m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); - - m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; - - // Return the new terrain to the world of physical objects - m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody); - - // redo its bounding box now that it is in the world - m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody); - - // Make it so the terrain will not move or be considered for movement. - m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); - - return; - } - - // If there is information in m_mapInfo pointing to physical structures, release same. - private void ReleaseHeightMapTerrain() - { - if (m_mapInfo != null) - { - if (m_mapInfo.terrainBody.HasPhysicalBody) + Vector3 minTerrainCoords = new Vector3(0f, 0f, BSTerrainManager.HEIGHT_INITIALIZATION - BSTerrainManager.HEIGHT_EQUAL_FUDGE); + Vector3 maxTerrainCoords = new Vector3(regionSize.X, regionSize.Y, BSTerrainManager.HEIGHT_INITIALIZATION); + int totalHeights = (int)maxTerrainCoords.X * (int)maxTerrainCoords.Y; + float[] initialMap = new float[totalHeights]; + for (int ii = 0; ii < totalHeights; ii++) { - m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody); - // Frees both the body and the shape. - m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody); + initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; } - m_mapInfo.Release(); + m_mapInfo = new BulletHMapInfo(id, initialMap, regionSize.X, regionSize.Y); + m_mapInfo.minCoords = minTerrainCoords; + m_mapInfo.maxCoords = maxTerrainCoords; + m_mapInfo.terrainRegionBase = TerrainBase; + // Don't have to free any previous since we just got here. + BuildHeightmapTerrain(); } - m_mapInfo = null; - } - // The passed position is relative to the base of the region. - // There are many assumptions herein that the heightmap increment is 1. - public override float GetTerrainHeightAtXYZ(Vector3 pos) - { - float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; - - try { - int baseX = (int)pos.X; - int baseY = (int)pos.Y; - int maxX = (int)m_mapInfo.sizeX; - int maxY = (int)m_mapInfo.sizeY; - float diffX = pos.X - (float)baseX; - float diffY = pos.Y - (float)baseY; - - float mapHeight1 = m_mapInfo.heightMap[baseY * maxY + baseX]; - float mapHeight2 = m_mapInfo.heightMap[Math.Min(baseY + 1, maxY - 1) * maxY + baseX]; - float mapHeight3 = m_mapInfo.heightMap[baseY * maxY + Math.Min(baseX + 1, maxX - 1)]; - float mapHeight4 = m_mapInfo.heightMap[Math.Min(baseY + 1, maxY - 1) * maxY + Math.Min(baseX + 1, maxX - 1)]; - - float Xrise = (mapHeight4 - mapHeight3) * diffX; - float Yrise = (mapHeight2 - mapHeight1) * diffY; - - ret = mapHeight1 + ((Xrise + Yrise) / 2f); - // m_physicsScene.DetailLog("{0},BSTerrainHeightMap,GetTerrainHeightAtXYZ,pos={1},{2}/{3}/{4}/{5},ret={6}", - // BSScene.DetailLogZero, pos, mapHeight1, mapHeight2, mapHeight3, mapHeight4, ret); - } - catch + // This minCoords and maxCoords passed in give the size of the terrain (min and max Z + // are the high and low points of the heightmap). + public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, + Vector3 minCoords, Vector3 maxCoords) + : base(physicsScene, regionBase, id) { - // Sometimes they give us wonky values of X and Y. Give a warning and return something. - m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", - LogHeader, m_mapInfo.terrainRegionBase, pos); - ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; - } - return ret; - } + m_mapInfo = new BulletHMapInfo(id, initialMap, maxCoords.X - minCoords.X, maxCoords.Y - minCoords.Y); + m_mapInfo.minCoords = minCoords; + m_mapInfo.maxCoords = maxCoords; + m_mapInfo.minZ = minCoords.Z; + m_mapInfo.maxZ = maxCoords.Z; + m_mapInfo.terrainRegionBase = TerrainBase; - // The passed position is relative to the base of the region. - public override float GetWaterLevelAtXYZ(Vector3 pos) - { - return m_physicsScene.SimpleWaterLevel; + // Don't have to free any previous since we just got here. + BuildHeightmapTerrain(); + } + + public override void Dispose() + { + ReleaseHeightMapTerrain(); + } + + // Using the information in m_mapInfo, create the physical representation of the heightmap. + private void BuildHeightmapTerrain() + { + // Create the terrain shape from the mapInfo + m_mapInfo.terrainShape = m_physicsScene.PE.CreateTerrainShape( m_mapInfo.ID, + new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ, + m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin); + + + // The terrain object initial position is at the center of the object + Vector3 centerPos; + centerPos.X = m_mapInfo.minCoords.X + (m_mapInfo.sizeX / 2f); + centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); + centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); + + m_mapInfo.terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape, + m_mapInfo.ID, centerPos, Quaternion.Identity); + + // Set current terrain attributes + m_physicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction); + m_physicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction); + m_physicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution); + m_physicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT); + + m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; + + // Return the new terrain to the world of physical objects + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_mapInfo.terrainBody); + + // redo its bounding box now that it is in the world + m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_mapInfo.terrainBody); + + // Make it so the terrain will not move or be considered for movement. + m_physicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION); + + return; + } + + // If there is information in m_mapInfo pointing to physical structures, release same. + private void ReleaseHeightMapTerrain() + { + if (m_mapInfo != null) + { + if (m_mapInfo.terrainBody.HasPhysicalBody) + { + m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_mapInfo.terrainBody); + // Frees both the body and the shape. + m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_mapInfo.terrainBody); + } + m_mapInfo.Release(); + } + m_mapInfo = null; + } + + // The passed position is relative to the base of the region. + // There are many assumptions herein that the heightmap increment is 1. + public override float GetTerrainHeightAtXYZ(Vector3 pos) + { + float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; + + try { + int baseX = (int)pos.X; + int baseY = (int)pos.Y; + int maxX = (int)m_mapInfo.sizeX; + int maxY = (int)m_mapInfo.sizeY; + float diffX = pos.X - (float)baseX; + float diffY = pos.Y - (float)baseY; + + float mapHeight1 = m_mapInfo.heightMap[baseY * maxY + baseX]; + float mapHeight2 = m_mapInfo.heightMap[Math.Min(baseY + 1, maxY - 1) * maxY + baseX]; + float mapHeight3 = m_mapInfo.heightMap[baseY * maxY + Math.Min(baseX + 1, maxX - 1)]; + float mapHeight4 = m_mapInfo.heightMap[Math.Min(baseY + 1, maxY - 1) * maxY + Math.Min(baseX + 1, maxX - 1)]; + + float Xrise = (mapHeight4 - mapHeight3) * diffX; + float Yrise = (mapHeight2 - mapHeight1) * diffY; + + ret = mapHeight1 + ((Xrise + Yrise) / 2f); + // m_physicsScene.DetailLog("{0},BSTerrainHeightMap,GetTerrainHeightAtXYZ,pos={1},{2}/{3}/{4}/{5},ret={6}", + // BSScene.DetailLogZero, pos, mapHeight1, mapHeight2, mapHeight3, mapHeight4, ret); + } + catch + { + // Sometimes they give us wonky values of X and Y. Give a warning and return something. + m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", + LogHeader, m_mapInfo.terrainRegionBase, pos); + ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; + } + return ret; + } + + // The passed position is relative to the base of the region. + public override float GetWaterLevelAtXYZ(Vector3 pos) + { + return m_physicsScene.SimpleWaterLevel; + } } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs index d11baa6cef..dc7d6470da 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainManager.cs @@ -39,546 +39,545 @@ using OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { - -// The physical implementation of the terrain is wrapped in this class. -public abstract class BSTerrainPhys : IDisposable -{ - public enum TerrainImplementation + // The physical implementation of the terrain is wrapped in this class. + public abstract class BSTerrainPhys : IDisposable { - Heightmap = 0, - Mesh = 1 - } - - protected BSScene m_physicsScene { get; private set; } - // Base of the region in world coordinates. Coordinates inside the region are relative to this. - public Vector3 TerrainBase { get; private set; } - public uint ID { get; private set; } - - public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) - { - m_physicsScene = physicsScene; - TerrainBase = regionBase; - ID = id; - } - public abstract void Dispose(); - public abstract float GetTerrainHeightAtXYZ(Vector3 pos); - public abstract float GetWaterLevelAtXYZ(Vector3 pos); -} - -// ========================================================================================== -public sealed class BSTerrainManager : IDisposable -{ - static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; - - // These height values are fractional so the odd values will be - // noticable when debugging. - public const float HEIGHT_INITIALIZATION = 24.987f; - public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; - public const float HEIGHT_GETHEIGHT_RET = 24.765f; - public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f; - - // If the min and max height are equal, we reduce the min by this - // amount to make sure that a bounding box is built for the terrain. - public const float HEIGHT_EQUAL_FUDGE = 0.2f; - - // Until the whole simulator is changed to pass us the region size, we rely on constants. - public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); - - // The scene that I am part of - private BSScene m_physicsScene { get; set; } - - // The ground plane created to keep thing from falling to infinity. - private BulletBody m_groundPlane; - - // If doing mega-regions, if we're region zero we will be managing multiple - // region terrains since region zero does the physics for the whole mega-region. - private Dictionary m_terrains; - - // Flags used to know when to recalculate the height. - private bool m_terrainModified = false; - - // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. - // This is incremented before assigning to new region so it is the last ID allocated. - private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1; - public uint HighestTerrainID { get {return m_terrainCount; } } - - // If doing mega-regions, this holds our offset from region zero of - // the mega-regions. "parentScene" points to the PhysicsScene of region zero. - private Vector3 m_worldOffset; - // If the parent region (region 0), this is the extent of the combined regions - // relative to the origin of region zero - private Vector3 m_worldMax; - private PhysicsScene MegaRegionParentPhysicsScene { get; set; } - - public BSTerrainManager(BSScene physicsScene, Vector3 regionSize) - { - m_physicsScene = physicsScene; - DefaultRegionSize = regionSize; - - m_terrains = new Dictionary(); - - // Assume one region of default size - m_worldOffset = Vector3.Zero; - m_worldMax = new Vector3(DefaultRegionSize); - MegaRegionParentPhysicsScene = null; - } - - public void Dispose() - { - ReleaseGroundPlaneAndTerrain(); - } - - // Create the initial instance of terrain and the underlying ground plane. - // This is called from the initialization routine so we presume it is - // safe to call Bullet in real time. We hope no one is moving prims around yet. - public void CreateInitialGroundPlaneAndTerrain() - { - DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); - // The ground plane is here to catch things that are trying to drop to negative infinity - BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); - Vector3 groundPlaneAltitude = new Vector3(0f, 0f, BSParam.TerrainGroundPlane); - m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, - BSScene.GROUNDPLANE_ID, groundPlaneAltitude, Quaternion.Identity); - - // Everything collides with the ground plane. - m_groundPlane.collisionType = CollisionType.Groundplane; - - m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane); - m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane); - - // Ground plane does not move - m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); - - BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); - lock (m_terrains) + public enum TerrainImplementation { - // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. - m_terrains.Add(Vector3.Zero, initialTerrain); + Heightmap = 0, + Mesh = 1 } + + protected BSScene m_physicsScene { get; private set; } + // Base of the region in world coordinates. Coordinates inside the region are relative to this. + public Vector3 TerrainBase { get; private set; } + public uint ID { get; private set; } + + public BSTerrainPhys(BSScene physicsScene, Vector3 regionBase, uint id) + { + m_physicsScene = physicsScene; + TerrainBase = regionBase; + ID = id; + } + public abstract void Dispose(); + public abstract float GetTerrainHeightAtXYZ(Vector3 pos); + public abstract float GetWaterLevelAtXYZ(Vector3 pos); } - // Release all the terrain structures we might have allocated - public void ReleaseGroundPlaneAndTerrain() + // ========================================================================================== + public sealed class BSTerrainManager : IDisposable { - DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); - if (m_groundPlane.HasPhysicalBody) + static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; + + // These height values are fractional so the odd values will be + // noticable when debugging. + public const float HEIGHT_INITIALIZATION = 24.987f; + public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; + public const float HEIGHT_GETHEIGHT_RET = 24.765f; + public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f; + + // If the min and max height are equal, we reduce the min by this + // amount to make sure that a bounding box is built for the terrain. + public const float HEIGHT_EQUAL_FUDGE = 0.2f; + + // Until the whole simulator is changed to pass us the region size, we rely on constants. + public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); + + // The scene that I am part of + private BSScene m_physicsScene { get; set; } + + // The ground plane created to keep thing from falling to infinity. + private BulletBody m_groundPlane; + + // If doing mega-regions, if we're region zero we will be managing multiple + // region terrains since region zero does the physics for the whole mega-region. + private Dictionary m_terrains; + + // Flags used to know when to recalculate the height. + private bool m_terrainModified = false; + + // If we are doing mega-regions, terrains are added from TERRAIN_ID to m_terrainCount. + // This is incremented before assigning to new region so it is the last ID allocated. + private uint m_terrainCount = BSScene.CHILDTERRAIN_ID - 1; + public uint HighestTerrainID { get {return m_terrainCount; } } + + // If doing mega-regions, this holds our offset from region zero of + // the mega-regions. "parentScene" points to the PhysicsScene of region zero. + private Vector3 m_worldOffset; + // If the parent region (region 0), this is the extent of the combined regions + // relative to the origin of region zero + private Vector3 m_worldMax; + private PhysicsScene MegaRegionParentPhysicsScene { get; set; } + + public BSTerrainManager(BSScene physicsScene, Vector3 regionSize) { - if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane)) + m_physicsScene = physicsScene; + DefaultRegionSize = regionSize; + + m_terrains = new Dictionary(); + + // Assume one region of default size + m_worldOffset = Vector3.Zero; + m_worldMax = new Vector3(DefaultRegionSize); + MegaRegionParentPhysicsScene = null; + } + + public void Dispose() + { + ReleaseGroundPlaneAndTerrain(); + } + + // Create the initial instance of terrain and the underlying ground plane. + // This is called from the initialization routine so we presume it is + // safe to call Bullet in real time. We hope no one is moving prims around yet. + public void CreateInitialGroundPlaneAndTerrain() + { + DetailLog("{0},BSTerrainManager.CreateInitialGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); + // The ground plane is here to catch things that are trying to drop to negative infinity + BulletShape groundPlaneShape = m_physicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin); + Vector3 groundPlaneAltitude = new Vector3(0f, 0f, BSParam.TerrainGroundPlane); + m_groundPlane = m_physicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape, + BSScene.GROUNDPLANE_ID, groundPlaneAltitude, Quaternion.Identity); + + // Everything collides with the ground plane. + m_groundPlane.collisionType = CollisionType.Groundplane; + + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_groundPlane); + m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_groundPlane); + + // Ground plane does not move + m_physicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION); + + BSTerrainPhys initialTerrain = new BSTerrainHeightmap(m_physicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); + lock (m_terrains) { - m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane); + // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. + m_terrains.Add(Vector3.Zero, initialTerrain); } - m_groundPlane.Clear(); } - ReleaseTerrain(); - } - - // Release all the terrain we have allocated - public void ReleaseTerrain() - { - lock (m_terrains) + // Release all the terrain structures we might have allocated + public void ReleaseGroundPlaneAndTerrain() { - foreach (KeyValuePair kvp in m_terrains) + DetailLog("{0},BSTerrainManager.ReleaseGroundPlaneAndTerrain,region={1}", BSScene.DetailLogZero, m_physicsScene.RegionName); + if (m_groundPlane.HasPhysicalBody) { - kvp.Value.Dispose(); - } - m_terrains.Clear(); - } - } - - // The simulator wants to set a new heightmap for the terrain. - public void SetTerrain(float[] heightMap) { - float[] localHeightMap = heightMap; - // If there are multiple requests for changes to the same terrain between ticks, - // only do that last one. - m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() - { - if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) - { - // If a child of a mega-region, we shouldn't have any terrain allocated for us - ReleaseGroundPlaneAndTerrain(); - // If doing the mega-prim stuff and we are the child of the zero region, - // the terrain is added to our parent - if (MegaRegionParentPhysicsScene is BSScene) + if (m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_groundPlane)) { - DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax); - ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain( - BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); + m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_groundPlane); } + m_groundPlane.Clear(); } - else - { - // If not doing the mega-prim thing, just change the terrain - DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); - UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); - } - }); - } - - // Another region is calling this region and passing a terrain. - // A region that is not the mega-region root will pass its terrain to the root region so the root region - // physics engine will have all the terrains. - private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) - { - // Since we are called by another region's thread, the action must be rescheduled onto our processing thread. - m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate() - { - UpdateTerrain(id, heightMap, minCoords, maxCoords); - }); - } - - // If called for terrain has has not been previously allocated, a new terrain will be built - // based on the passed information. The 'id' should be either the terrain id or - // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. - // The latter feature is for creating child terrains for mega-regions. - // If there is an existing terrain body, a new - // terrain shape is created and added to the body. - // This call is most often used to update the heightMap and parameters of the terrain. - // (The above does suggest that some simplification/refactoring is in order.) - // Called during taint-time. - private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) - { - // Find high and low points of passed heightmap. - // The min and max passed in is usually the area objects can be in (maximum - // object height, for instance). The terrain wants the bounding box for the - // terrain so replace passed min and max Z with the actual terrain min/max Z. - float minZ = float.MaxValue; - float maxZ = float.MinValue; - foreach (float height in heightMap) - { - if (height < minZ) minZ = height; - if (height > maxZ) maxZ = height; + ReleaseTerrain(); } - if (minZ == maxZ) + + // Release all the terrain we have allocated + public void ReleaseTerrain() { - // If min and max are the same, reduce min a little bit so a good bounding box is created. - minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE; - } - minCoords.Z = minZ; - maxCoords.Z = maxZ; - - DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}", - BSScene.DetailLogZero, id, minCoords, maxCoords); - - Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); - - lock (m_terrains) - { - BSTerrainPhys terrainPhys; - if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) + lock (m_terrains) { - // There is already a terrain in this spot. Free the old and build the new. - DetailLog("{0},BSTerrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", - BSScene.DetailLogZero, id, terrainRegionBase, minCoords, maxCoords); - - // Remove old terrain from the collection - m_terrains.Remove(terrainRegionBase); - // Release any physical memory it may be using. - terrainPhys.Dispose(); - - if (MegaRegionParentPhysicsScene == null) + foreach (KeyValuePair kvp in m_terrains) { - // This terrain is not part of the mega-region scheme. Create vanilla terrain. + kvp.Value.Dispose(); + } + m_terrains.Clear(); + } + } + + // The simulator wants to set a new heightmap for the terrain. + public void SetTerrain(float[] heightMap) { + float[] localHeightMap = heightMap; + // If there are multiple requests for changes to the same terrain between ticks, + // only do that last one. + m_physicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() + { + if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) + { + // If a child of a mega-region, we shouldn't have any terrain allocated for us + ReleaseGroundPlaneAndTerrain(); + // If doing the mega-prim stuff and we are the child of the zero region, + // the terrain is added to our parent + if (MegaRegionParentPhysicsScene is BSScene) + { + DetailLog("{0},SetTerrain.ToParent,offset={1},worldMax={2}", BSScene.DetailLogZero, m_worldOffset, m_worldMax); + ((BSScene)MegaRegionParentPhysicsScene).TerrainManager.AddMegaRegionChildTerrain( + BSScene.CHILDTERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); + } + } + else + { + // If not doing the mega-prim thing, just change the terrain + DetailLog("{0},SetTerrain.Existing", BSScene.DetailLogZero); + + UpdateTerrain(BSScene.TERRAIN_ID, localHeightMap, m_worldOffset, m_worldOffset + DefaultRegionSize); + } + }); + } + + // Another region is calling this region and passing a terrain. + // A region that is not the mega-region root will pass its terrain to the root region so the root region + // physics engine will have all the terrains. + private void AddMegaRegionChildTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) + { + // Since we are called by another region's thread, the action must be rescheduled onto our processing thread. + m_physicsScene.PostTaintObject("TerrainManager.AddMegaRegionChild" + minCoords.ToString(), id, delegate() + { + UpdateTerrain(id, heightMap, minCoords, maxCoords); + }); + } + + // If called for terrain has has not been previously allocated, a new terrain will be built + // based on the passed information. The 'id' should be either the terrain id or + // BSScene.CHILDTERRAIN_ID. If the latter, a new child terrain ID will be allocated and used. + // The latter feature is for creating child terrains for mega-regions. + // If there is an existing terrain body, a new + // terrain shape is created and added to the body. + // This call is most often used to update the heightMap and parameters of the terrain. + // (The above does suggest that some simplification/refactoring is in order.) + // Called during taint-time. + private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) + { + // Find high and low points of passed heightmap. + // The min and max passed in is usually the area objects can be in (maximum + // object height, for instance). The terrain wants the bounding box for the + // terrain so replace passed min and max Z with the actual terrain min/max Z. + float minZ = float.MaxValue; + float maxZ = float.MinValue; + foreach (float height in heightMap) + { + if (height < minZ) minZ = height; + if (height > maxZ) maxZ = height; + } + if (minZ == maxZ) + { + // If min and max are the same, reduce min a little bit so a good bounding box is created. + minZ -= BSTerrainManager.HEIGHT_EQUAL_FUDGE; + } + minCoords.Z = minZ; + maxCoords.Z = maxZ; + + DetailLog("{0},BSTerrainManager.UpdateTerrain,call,id={1},minC={2},maxC={3}", + BSScene.DetailLogZero, id, minCoords, maxCoords); + + Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); + + lock (m_terrains) + { + BSTerrainPhys terrainPhys; + if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) + { + // There is already a terrain in this spot. Free the old and build the new. + DetailLog("{0},BSTerrainManager.UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", + BSScene.DetailLogZero, id, terrainRegionBase, minCoords, maxCoords); + + // Remove old terrain from the collection + m_terrains.Remove(terrainRegionBase); + // Release any physical memory it may be using. + terrainPhys.Dispose(); + + if (MegaRegionParentPhysicsScene == null) + { + // This terrain is not part of the mega-region scheme. Create vanilla terrain. + BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); + m_terrains.Add(terrainRegionBase, newTerrainPhys); + + m_terrainModified = true; + } + else + { + // It's possible that Combine() was called after this code was queued. + // If we are a child of combined regions, we don't create any terrain for us. + DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero); + + // Get rid of any terrain that may have been allocated for us. + ReleaseGroundPlaneAndTerrain(); + + // I hate doing this, but just bail + return; + } + } + else + { + // We don't know about this terrain so either we are creating a new terrain or + // our mega-prim child is giving us a new terrain to add to the phys world + + // if this is a child terrain, calculate a unique terrain id + uint newTerrainID = id; + if (newTerrainID >= BSScene.CHILDTERRAIN_ID) + newTerrainID = ++m_terrainCount; + + DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", + BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords); BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); m_terrains.Add(terrainRegionBase, newTerrainPhys); m_terrainModified = true; } - else + } + } + + // TODO: redo terrain implementation selection to allow other base types than heightMap. + private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) + { + m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", + LogHeader, m_physicsScene.RegionName, terrainRegionBase, + (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); + BSTerrainPhys newTerrainPhys = null; + switch ((int)BSParam.TerrainImplementation) + { + case (int)BSTerrainPhys.TerrainImplementation.Heightmap: + newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id, + heightMap, minCoords, maxCoords); + break; + case (int)BSTerrainPhys.TerrainImplementation.Mesh: + newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id, + heightMap, minCoords, maxCoords); + break; + default: + m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", + LogHeader, + (int)BSParam.TerrainImplementation, + BSParam.TerrainImplementation, + m_physicsScene.RegionName, terrainRegionBase); + break; + } + return newTerrainPhys; + } + + // Return 'true' of this position is somewhere in known physical terrain space + public bool IsWithinKnownTerrain(Vector3 pos) + { + Vector3 terrainBaseXYZ; + BSTerrainPhys physTerrain; + return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); + } + + // Return a new position that is over known terrain if the position is outside our terrain. + public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos) + { + float edgeEpsilon = 0.1f; + + Vector3 ret = pPos; + + // First, base addresses are never negative so correct for that possible problem. + if (ret.X < 0f || ret.Y < 0f) + { + ret.X = Util.Clamp(ret.X, 0f, 1000000f); + ret.Y = Util.Clamp(ret.Y, 0f, 1000000f); + DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}", + BSScene.DetailLogZero, pPos, ret); + } + + // Can't do this function if we don't know about any terrain. + if (m_terrains.Count == 0) + return ret; + + int loopPrevention = 10; + Vector3 terrainBaseXYZ; + BSTerrainPhys physTerrain; + while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ)) + { + // The passed position is not within a known terrain area. + // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region. + + // Must be off the top of a region. Find an adjacent region to move into. + // The returned terrain is always 'lower'. That is, closer to <0,0>. + Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ); + + if (adjacentTerrainBase.X < terrainBaseXYZ.X) { - // It's possible that Combine() was called after this code was queued. - // If we are a child of combined regions, we don't create any terrain for us. - DetailLog("{0},BSTerrainManager.UpdateTerrain:AmACombineChild,taint", BSScene.DetailLogZero); - - // Get rid of any terrain that may have been allocated for us. - ReleaseGroundPlaneAndTerrain(); - - // I hate doing this, but just bail - return; + // moving down into a new region in the X dimension. New position will be the max in the new base. + ret.X = adjacentTerrainBase.X + DefaultRegionSize.X - edgeEpsilon; } + if (adjacentTerrainBase.Y < terrainBaseXYZ.Y) + { + // moving down into a new region in the X dimension. New position will be the max in the new base. + ret.Y = adjacentTerrainBase.Y + DefaultRegionSize.Y - edgeEpsilon; + } + DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}", + BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret); + + if (loopPrevention-- < 0f) + { + // The 'while' is a little dangerous so this prevents looping forever if the + // mapping of the terrains ever gets messed up (like nothing at <0,0>) or + // the list of terrains is in transition. + DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero); + break; + } + } + + return ret; + } + + // Given an X and Y, find the height of the terrain. + // Since we could be handling multiple terrains for a mega-region, + // the base of the region is calcuated assuming all regions are + // the same size and that is the default. + // Once the heightMapInfo is found, we have all the information to + // compute the offset into the array. + private float lastHeightTX = 999999f; + private float lastHeightTY = 999999f; + private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; + public float GetTerrainHeightAtXYZ(Vector3 pos) + { + float tX = pos.X; + float tY = pos.Y; + // You'd be surprized at the number of times this routine is called + // with the same parameters as last time. + if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY)) + return lastHeight; + m_terrainModified = false; + + lastHeightTX = tX; + lastHeightTY = tY; + float ret = HEIGHT_GETHEIGHT_RET; + + Vector3 terrainBaseXYZ; + BSTerrainPhys physTerrain; + if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) + { + ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ); } else { - // We don't know about this terrain so either we are creating a new terrain or - // our mega-prim child is giving us a new terrain to add to the phys world - - // if this is a child terrain, calculate a unique terrain id - uint newTerrainID = id; - if (newTerrainID >= BSScene.CHILDTERRAIN_ID) - newTerrainID = ++m_terrainCount; - - DetailLog("{0},BSTerrainManager.UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", - BSScene.DetailLogZero, newTerrainID, minCoords, maxCoords); - BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); - m_terrains.Add(terrainRegionBase, newTerrainPhys); - - m_terrainModified = true; + m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", + LogHeader, m_physicsScene.RegionName, tX, tY); + DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", + BSScene.DetailLogZero, pos, terrainBaseXYZ); } + + lastHeight = ret; + return ret; } - } - // TODO: redo terrain implementation selection to allow other base types than heightMap. - private BSTerrainPhys BuildPhysicalTerrain(Vector3 terrainRegionBase, uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords) - { - m_physicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", - LogHeader, m_physicsScene.RegionName, terrainRegionBase, - (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation); - BSTerrainPhys newTerrainPhys = null; - switch ((int)BSParam.TerrainImplementation) + public float GetWaterLevelAtXYZ(Vector3 pos) { - case (int)BSTerrainPhys.TerrainImplementation.Heightmap: - newTerrainPhys = new BSTerrainHeightmap(m_physicsScene, terrainRegionBase, id, - heightMap, minCoords, maxCoords); - break; - case (int)BSTerrainPhys.TerrainImplementation.Mesh: - newTerrainPhys = new BSTerrainMesh(m_physicsScene, terrainRegionBase, id, - heightMap, minCoords, maxCoords); - break; - default: - m_physicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", - LogHeader, - (int)BSParam.TerrainImplementation, - BSParam.TerrainImplementation, - m_physicsScene.RegionName, terrainRegionBase); - break; + float ret = WATER_HEIGHT_GETHEIGHT_RET; + + Vector3 terrainBaseXYZ; + BSTerrainPhys physTerrain; + if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) + { + ret = physTerrain.GetWaterLevelAtXYZ(pos); + } + else + { + m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", + LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret); + } + return ret; } - return newTerrainPhys; - } - // Return 'true' of this position is somewhere in known physical terrain space - public bool IsWithinKnownTerrain(Vector3 pos) - { - Vector3 terrainBaseXYZ; - BSTerrainPhys physTerrain; - return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); - } - - // Return a new position that is over known terrain if the position is outside our terrain. - public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos) - { - float edgeEpsilon = 0.1f; - - Vector3 ret = pPos; - - // First, base addresses are never negative so correct for that possible problem. - if (ret.X < 0f || ret.Y < 0f) + // Given an address, return 'true' of there is a description of that terrain and output + // the descriptor class and the 'base' fo the addresses therein. + private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) { + bool ret = false; + + Vector3 terrainBaseXYZ = Vector3.Zero; + if (pos.X < 0f || pos.Y < 0f) + { + // We don't handle negative addresses so just make up a base that will not be found. + terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f); + } + else + { + int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; + int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; + terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); + } + + BSTerrainPhys physTerrain = null; + lock (m_terrains) + { + ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); + } + outTerrainBase = terrainBaseXYZ; + outPhysTerrain = physTerrain; + return ret; + } + + // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than + // this one. Usually used to return an out of bounds object to a known place. + private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase) + { + Vector3 ret = pTerrainBase; + + // Can't do this function if we don't know about any terrain. + if (m_terrains.Count == 0) + return ret; + + // Just some sanity ret.X = Util.Clamp(ret.X, 0f, 1000000f); ret.Y = Util.Clamp(ret.Y, 0f, 1000000f); - DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}", - BSScene.DetailLogZero, pPos, ret); - } + ret.Z = 0f; - // Can't do this function if we don't know about any terrain. - if (m_terrains.Count == 0) - return ret; - - int loopPrevention = 10; - Vector3 terrainBaseXYZ; - BSTerrainPhys physTerrain; - while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ)) - { - // The passed position is not within a known terrain area. - // NOTE that GetTerrainPhysicalAtXYZ will set 'terrainBaseXYZ' to the base of the unfound region. - - // Must be off the top of a region. Find an adjacent region to move into. - // The returned terrain is always 'lower'. That is, closer to <0,0>. - Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ); - - if (adjacentTerrainBase.X < terrainBaseXYZ.X) + lock (m_terrains) { - // moving down into a new region in the X dimension. New position will be the max in the new base. - ret.X = adjacentTerrainBase.X + DefaultRegionSize.X - edgeEpsilon; - } - if (adjacentTerrainBase.Y < terrainBaseXYZ.Y) - { - // moving down into a new region in the X dimension. New position will be the max in the new base. - ret.Y = adjacentTerrainBase.Y + DefaultRegionSize.Y - edgeEpsilon; - } - DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}", - BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret); - - if (loopPrevention-- < 0f) - { - // The 'while' is a little dangerous so this prevents looping forever if the - // mapping of the terrains ever gets messed up (like nothing at <0,0>) or - // the list of terrains is in transition. - DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero); - break; - } - } - - return ret; - } - - // Given an X and Y, find the height of the terrain. - // Since we could be handling multiple terrains for a mega-region, - // the base of the region is calcuated assuming all regions are - // the same size and that is the default. - // Once the heightMapInfo is found, we have all the information to - // compute the offset into the array. - private float lastHeightTX = 999999f; - private float lastHeightTY = 999999f; - private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; - public float GetTerrainHeightAtXYZ(Vector3 pos) - { - float tX = pos.X; - float tY = pos.Y; - // You'd be surprized at the number of times this routine is called - // with the same parameters as last time. - if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY)) - return lastHeight; - m_terrainModified = false; - - lastHeightTX = tX; - lastHeightTY = tY; - float ret = HEIGHT_GETHEIGHT_RET; - - Vector3 terrainBaseXYZ; - BSTerrainPhys physTerrain; - if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) - { - ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ); - } - else - { - m_physicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", - LogHeader, m_physicsScene.RegionName, tX, tY); - DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", - BSScene.DetailLogZero, pos, terrainBaseXYZ); - } - - lastHeight = ret; - return ret; - } - - public float GetWaterLevelAtXYZ(Vector3 pos) - { - float ret = WATER_HEIGHT_GETHEIGHT_RET; - - Vector3 terrainBaseXYZ; - BSTerrainPhys physTerrain; - if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) - { - ret = physTerrain.GetWaterLevelAtXYZ(pos); - } - else - { - m_physicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", - LogHeader, m_physicsScene.RegionName, pos, terrainBaseXYZ, ret); - } - return ret; - } - - // Given an address, return 'true' of there is a description of that terrain and output - // the descriptor class and the 'base' fo the addresses therein. - private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) - { - bool ret = false; - - Vector3 terrainBaseXYZ = Vector3.Zero; - if (pos.X < 0f || pos.Y < 0f) - { - // We don't handle negative addresses so just make up a base that will not be found. - terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f); - } - else - { - int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; - int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; - terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); - } - - BSTerrainPhys physTerrain = null; - lock (m_terrains) - { - ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); - } - outTerrainBase = terrainBaseXYZ; - outPhysTerrain = physTerrain; - return ret; - } - - // Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than - // this one. Usually used to return an out of bounds object to a known place. - private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase) - { - Vector3 ret = pTerrainBase; - - // Can't do this function if we don't know about any terrain. - if (m_terrains.Count == 0) - return ret; - - // Just some sanity - ret.X = Util.Clamp(ret.X, 0f, 1000000f); - ret.Y = Util.Clamp(ret.Y, 0f, 1000000f); - ret.Z = 0f; - - lock (m_terrains) - { - // Once down to the <0,0> region, we have to be done. - while (ret.X > 0f || ret.Y > 0f) - { - if (ret.X > 0f) + // Once down to the <0,0> region, we have to be done. + while (ret.X > 0f || ret.Y > 0f) { - ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X); - DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret); - if (m_terrains.ContainsKey(ret)) - break; - } - if (ret.Y > 0f) - { - ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y); - DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret); - if (m_terrains.ContainsKey(ret)) - break; + if (ret.X > 0f) + { + ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X); + DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret); + if (m_terrains.ContainsKey(ret)) + break; + } + if (ret.Y > 0f) + { + ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y); + DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret); + if (m_terrains.ContainsKey(ret)) + break; + } } } + + return ret; } - return ret; - } - - // Although no one seems to check this, I do support combining. - public bool SupportsCombining() - { - return true; - } - - // This routine is called two ways: - // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum - // extent of the combined regions. This is to inform the parent of the size - // of the combined regions. - // and one with 'offset' as the offset of the child region to the base region, - // 'pScene' pointing to the parent and 'extents' of zero. This informs the - // child of its relative base and new parent. - public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) - { - m_worldOffset = offset; - m_worldMax = extents; - MegaRegionParentPhysicsScene = pScene; - if (pScene != null) + // Although no one seems to check this, I do support combining. + public bool SupportsCombining() { - // We are a child. - // We want m_worldMax to be the highest coordinate of our piece of terrain. - m_worldMax = offset + DefaultRegionSize; + return true; } - DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}", - BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax); - } - // Unhook all the combining that I know about. - public void UnCombine(PhysicsScene pScene) - { - // Just like ODE, we don't do anything yet. - DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero); - } + // This routine is called two ways: + // One with 'offset' and 'pScene' zero and null but 'extents' giving the maximum + // extent of the combined regions. This is to inform the parent of the size + // of the combined regions. + // and one with 'offset' as the offset of the child region to the base region, + // 'pScene' pointing to the parent and 'extents' of zero. This informs the + // child of its relative base and new parent. + public void Combine(PhysicsScene pScene, Vector3 offset, Vector3 extents) + { + m_worldOffset = offset; + m_worldMax = extents; + MegaRegionParentPhysicsScene = pScene; + if (pScene != null) + { + // We are a child. + // We want m_worldMax to be the highest coordinate of our piece of terrain. + m_worldMax = offset + DefaultRegionSize; + } + DetailLog("{0},BSTerrainManager.Combine,offset={1},extents={2},wOffset={3},wMax={4}", + BSScene.DetailLogZero, offset, extents, m_worldOffset, m_worldMax); + } + + // Unhook all the combining that I know about. + public void UnCombine(PhysicsScene pScene) + { + // Just like ODE, we don't do anything yet. + DetailLog("{0},BSTerrainManager.UnCombine", BSScene.DetailLogZero); + } - private void DetailLog(string msg, params Object[] args) - { - m_physicsScene.PhysicsLogging.Write(msg, args); + private void DetailLog(string msg, params Object[] args) + { + m_physicsScene.PhysicsLogging.Write(msg, args); + } } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs index cd59b656ea..3afebbc587 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSTerrainMesh.cs @@ -39,402 +39,402 @@ using OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -public sealed class BSTerrainMesh : BSTerrainPhys -{ - static string LogHeader = "[BULLETSIM TERRAIN MESH]"; - - private float[] m_savedHeightMap; - int m_sizeX; - int m_sizeY; - - BulletShape m_terrainShape; - BulletBody m_terrainBody; - - public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) - : base(physicsScene, regionBase, id) + public sealed class BSTerrainMesh : BSTerrainPhys { - } + static string LogHeader = "[BULLETSIM TERRAIN MESH]"; - public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */) - : base(physicsScene, regionBase, id) - { - } + private float[] m_savedHeightMap; + int m_sizeX; + int m_sizeY; - // Create terrain mesh from a heightmap. - public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, - Vector3 minCoords, Vector3 maxCoords) - : base(physicsScene, regionBase, id) - { - int indicesCount; - int[] indices; - int verticesCount; - float[] vertices; + BulletShape m_terrainShape; + BulletBody m_terrainBody; - m_savedHeightMap = initialMap; - - m_sizeX = (int)(maxCoords.X - minCoords.X); - m_sizeY = (int)(maxCoords.Y - minCoords.Y); - - bool meshCreationSuccess = false; - if (BSParam.TerrainMeshMagnification == 1) + public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) + : base(physicsScene, regionBase, id) { - // If a magnification of one, use the old routine that is tried and true. - meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene, - initialMap, m_sizeX, m_sizeY, // input size - Vector3.Zero, // base for mesh - out indicesCount, out indices, out verticesCount, out vertices); - } - else - { - // Other magnifications use the newer routine - meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene, - initialMap, m_sizeX, m_sizeY, // input size - BSParam.TerrainMeshMagnification, - physicsScene.TerrainManager.DefaultRegionSize, - Vector3.Zero, // base for mesh - out indicesCount, out indices, out verticesCount, out vertices); - } - if (!meshCreationSuccess) - { - // DISASTER!! - m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); - m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); - // Something is very messed up and a crash is in our future. - return; } - m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", - BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length); - - m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices); - if (!m_terrainShape.HasPhysicalShape) + public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id /* parameters for making mesh */) + : base(physicsScene, regionBase, id) { - // DISASTER!! - m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); - m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); - // Something is very messed up and a crash is in our future. - return; } - Vector3 pos = regionBase; - Quaternion rot = Quaternion.Identity; - - m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); - if (!m_terrainBody.HasPhysicalBody) + // Create terrain mesh from a heightmap. + public BSTerrainMesh(BSScene physicsScene, Vector3 regionBase, uint id, float[] initialMap, + Vector3 minCoords, Vector3 maxCoords) + : base(physicsScene, regionBase, id) { - // DISASTER!! - m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); - // Something is very messed up and a crash is in our future. - return; - } - physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin); + int indicesCount; + int[] indices; + int verticesCount; + float[] vertices; - // Set current terrain attributes - m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); - m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); - m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); - m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold); - m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); + m_savedHeightMap = initialMap; - // Static objects are not very massive. - m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); + m_sizeX = (int)(maxCoords.X - minCoords.X); + m_sizeY = (int)(maxCoords.Y - minCoords.Y); - // Put the new terrain to the world of physical objects - m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody); - - // Redo its bounding box now that it is in the world - m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody); - - m_terrainBody.collisionType = CollisionType.Terrain; - m_terrainBody.ApplyCollisionMask(m_physicsScene); - - if (BSParam.UseSingleSidedMeshes) - { - m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); - m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); - } - - // Make it so the terrain will not move or be considered for movement. - m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); - } - - public override void Dispose() - { - if (m_terrainBody.HasPhysicalBody) - { - m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody); - // Frees both the body and the shape. - m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody); - m_terrainBody.Clear(); - m_terrainShape.Clear(); - } - } - - public override float GetTerrainHeightAtXYZ(Vector3 pos) - { - // For the moment use the saved heightmap to get the terrain height. - // TODO: raycast downward to find the true terrain below the position. - float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; - - int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X; - try - { - ret = m_savedHeightMap[mapIndex]; - } - catch - { - // Sometimes they give us wonky values of X and Y. Give a warning and return something. - m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", - LogHeader, TerrainBase, pos); - ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; - } - return ret; - } - - // The passed position is relative to the base of the region. - public override float GetWaterLevelAtXYZ(Vector3 pos) - { - return m_physicsScene.SimpleWaterLevel; - } - - // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). - // Return 'true' if successfully created. - public static bool ConvertHeightmapToMesh( BSScene physicsScene, - float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap - Vector3 extentBase, // base to be added to all vertices - out int indicesCountO, out int[] indicesO, - out int verticesCountO, out float[] verticesO) - { - bool ret = false; - - int indicesCount = 0; - int verticesCount = 0; - int[] indices = new int[0]; - float[] vertices = new float[0]; - - // Simple mesh creation which assumes magnification == 1. - // TODO: do a more general solution that scales, adds new vertices and smoothes the result. - - // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop - // from zero to <= sizeX). The triangle indices are then generated as two triangles - // per heightmap point. There are sizeX by sizeY of these squares. The extra row and - // column of vertices are used to complete the triangles of the last row and column - // of the heightmap. - try - { - // One vertice per heightmap value plus the vertices off the side and bottom edge. - int totalVertices = (sizeX + 1) * (sizeY + 1); - vertices = new float[totalVertices * 3]; - int totalIndices = sizeX * sizeY * 6; - indices = new int[totalIndices]; - - if (physicsScene != null) - physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}", - BSScene.DetailLogZero, totalVertices, totalIndices, extentBase); - float minHeight = float.MaxValue; - // Note that sizeX+1 vertices are created since there is land between this and the next region. - for (int yy = 0; yy <= sizeY; yy++) + bool meshCreationSuccess = false; + if (BSParam.TerrainMeshMagnification == 1) { - for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times - { - int offset = yy * sizeX + xx; - // Extend the height with the height from the last row or column - if (yy == sizeY) offset -= sizeX; - if (xx == sizeX) offset -= 1; - float height = heightMap[offset]; - minHeight = Math.Min(minHeight, height); - vertices[verticesCount + 0] = (float)xx + extentBase.X; - vertices[verticesCount + 1] = (float)yy + extentBase.Y; - vertices[verticesCount + 2] = height + extentBase.Z; - verticesCount += 3; - } + // If a magnification of one, use the old routine that is tried and true. + meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh(m_physicsScene, + initialMap, m_sizeX, m_sizeY, // input size + Vector3.Zero, // base for mesh + out indicesCount, out indices, out verticesCount, out vertices); } - verticesCount = verticesCount / 3; - - for (int yy = 0; yy < sizeY; yy++) - { - for (int xx = 0; xx < sizeX; xx++) - { - int offset = yy * (sizeX + 1) + xx; - // Each vertices is presumed to be the upper left corner of a box of two triangles - indices[indicesCount + 0] = offset; - indices[indicesCount + 1] = offset + 1; - indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column - indices[indicesCount + 3] = offset + 1; - indices[indicesCount + 4] = offset + sizeX + 2; - indices[indicesCount + 5] = offset + sizeX + 1; - indicesCount += 6; - } - } - - ret = true; - } - catch (Exception e) - { - if (physicsScene != null) - physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", - LogHeader, physicsScene.RegionName, extentBase, e); - } - - indicesCountO = indicesCount; - indicesO = indices; - verticesCountO = verticesCount; - verticesO = vertices; - - return ret; - } - - private class HeightMapGetter - { - private float[] m_heightMap; - private int m_sizeX; - private int m_sizeY; - public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY) - { - m_heightMap = pHeightMap; - m_sizeX = pSizeX; - m_sizeY = pSizeY; - } - // The heightmap is extended as an infinite plane at the last height - public float GetHeight(int xx, int yy) - { - int offset = 0; - // Extend the height with the height from the last row or column - if (yy >= m_sizeY) - if (xx >= m_sizeX) - offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1); - else - offset = (m_sizeY - 1) * m_sizeX + xx; else - if (xx >= m_sizeX) - offset = yy * m_sizeX + (m_sizeX - 1); + { + // Other magnifications use the newer routine + meshCreationSuccess = BSTerrainMesh.ConvertHeightmapToMesh2(m_physicsScene, + initialMap, m_sizeX, m_sizeY, // input size + BSParam.TerrainMeshMagnification, + physicsScene.TerrainManager.DefaultRegionSize, + Vector3.Zero, // base for mesh + out indicesCount, out indices, out verticesCount, out vertices); + } + if (!meshCreationSuccess) + { + // DISASTER!! + m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedConversionOfHeightmap,id={1}", BSScene.DetailLogZero, ID); + m_physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh! base={1}", LogHeader, TerrainBase); + // Something is very messed up and a crash is in our future. + return; + } + + m_physicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,id={1},indices={2},indSz={3},vertices={4},vertSz={5}", + BSScene.DetailLogZero, ID, indicesCount, indices.Length, verticesCount, vertices.Length); + + m_terrainShape = m_physicsScene.PE.CreateMeshShape(m_physicsScene.World, indicesCount, indices, verticesCount, vertices); + if (!m_terrainShape.HasPhysicalShape) + { + // DISASTER!! + m_physicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape,id={1}", BSScene.DetailLogZero, ID); + m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain mesh! base={1}", LogHeader, TerrainBase); + // Something is very messed up and a crash is in our future. + return; + } + + Vector3 pos = regionBase; + Quaternion rot = Quaternion.Identity; + + m_terrainBody = m_physicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot); + if (!m_terrainBody.HasPhysicalBody) + { + // DISASTER!! + m_physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); + // Something is very messed up and a crash is in our future. + return; + } + physicsScene.PE.SetShapeCollisionMargin(m_terrainShape, BSParam.TerrainCollisionMargin); + + // Set current terrain attributes + m_physicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction); + m_physicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction); + m_physicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution); + m_physicsScene.PE.SetContactProcessingThreshold(m_terrainBody, BSParam.TerrainContactProcessingThreshold); + m_physicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT); + + // Static objects are not very massive. + m_physicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero); + + // Put the new terrain to the world of physical objects + m_physicsScene.PE.AddObjectToWorld(m_physicsScene.World, m_terrainBody); + + // Redo its bounding box now that it is in the world + m_physicsScene.PE.UpdateSingleAabb(m_physicsScene.World, m_terrainBody); + + m_terrainBody.collisionType = CollisionType.Terrain; + m_terrainBody.ApplyCollisionMask(m_physicsScene); + + if (BSParam.UseSingleSidedMeshes) + { + m_physicsScene.DetailLog("{0},BSTerrainMesh.settingCustomMaterial,id={1}", BSScene.DetailLogZero, id); + m_physicsScene.PE.AddToCollisionFlags(m_terrainBody, CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK); + } + + // Make it so the terrain will not move or be considered for movement. + m_physicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION); + } + + public override void Dispose() + { + if (m_terrainBody.HasPhysicalBody) + { + m_physicsScene.PE.RemoveObjectFromWorld(m_physicsScene.World, m_terrainBody); + // Frees both the body and the shape. + m_physicsScene.PE.DestroyObject(m_physicsScene.World, m_terrainBody); + m_terrainBody.Clear(); + m_terrainShape.Clear(); + } + } + + public override float GetTerrainHeightAtXYZ(Vector3 pos) + { + // For the moment use the saved heightmap to get the terrain height. + // TODO: raycast downward to find the true terrain below the position. + float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; + + int mapIndex = (int)pos.Y * m_sizeY + (int)pos.X; + try + { + ret = m_savedHeightMap[mapIndex]; + } + catch + { + // Sometimes they give us wonky values of X and Y. Give a warning and return something. + m_physicsScene.Logger.WarnFormat("{0} Bad request for terrain height. terrainBase={1}, pos={2}", + LogHeader, TerrainBase, pos); + ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; + } + return ret; + } + + // The passed position is relative to the base of the region. + public override float GetWaterLevelAtXYZ(Vector3 pos) + { + return m_physicsScene.SimpleWaterLevel; + } + + // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). + // Return 'true' if successfully created. + public static bool ConvertHeightmapToMesh( BSScene physicsScene, + float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap + Vector3 extentBase, // base to be added to all vertices + out int indicesCountO, out int[] indicesO, + out int verticesCountO, out float[] verticesO) + { + bool ret = false; + + int indicesCount = 0; + int verticesCount = 0; + int[] indices = new int[0]; + float[] vertices = new float[0]; + + // Simple mesh creation which assumes magnification == 1. + // TODO: do a more general solution that scales, adds new vertices and smoothes the result. + + // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop + // from zero to <= sizeX). The triangle indices are then generated as two triangles + // per heightmap point. There are sizeX by sizeY of these squares. The extra row and + // column of vertices are used to complete the triangles of the last row and column + // of the heightmap. + try + { + // One vertice per heightmap value plus the vertices off the side and bottom edge. + int totalVertices = (sizeX + 1) * (sizeY + 1); + vertices = new float[totalVertices * 3]; + int totalIndices = sizeX * sizeY * 6; + indices = new int[totalIndices]; + + if (physicsScene != null) + physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3}", + BSScene.DetailLogZero, totalVertices, totalIndices, extentBase); + float minHeight = float.MaxValue; + // Note that sizeX+1 vertices are created since there is land between this and the next region. + for (int yy = 0; yy <= sizeY; yy++) + { + for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times + { + int offset = yy * sizeX + xx; + // Extend the height with the height from the last row or column + if (yy == sizeY) offset -= sizeX; + if (xx == sizeX) offset -= 1; + float height = heightMap[offset]; + minHeight = Math.Min(minHeight, height); + vertices[verticesCount + 0] = (float)xx + extentBase.X; + vertices[verticesCount + 1] = (float)yy + extentBase.Y; + vertices[verticesCount + 2] = height + extentBase.Z; + verticesCount += 3; + } + } + verticesCount = verticesCount / 3; + + for (int yy = 0; yy < sizeY; yy++) + { + for (int xx = 0; xx < sizeX; xx++) + { + int offset = yy * (sizeX + 1) + xx; + // Each vertices is presumed to be the upper left corner of a box of two triangles + indices[indicesCount + 0] = offset; + indices[indicesCount + 1] = offset + 1; + indices[indicesCount + 2] = offset + sizeX + 1; // accounting for the extra column + indices[indicesCount + 3] = offset + 1; + indices[indicesCount + 4] = offset + sizeX + 2; + indices[indicesCount + 5] = offset + sizeX + 1; + indicesCount += 6; + } + } + + ret = true; + } + catch (Exception e) + { + if (physicsScene != null) + physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", + LogHeader, physicsScene.RegionName, extentBase, e); + } + + indicesCountO = indicesCount; + indicesO = indices; + verticesCountO = verticesCount; + verticesO = vertices; + + return ret; + } + + private class HeightMapGetter + { + private float[] m_heightMap; + private int m_sizeX; + private int m_sizeY; + public HeightMapGetter(float[] pHeightMap, int pSizeX, int pSizeY) + { + m_heightMap = pHeightMap; + m_sizeX = pSizeX; + m_sizeY = pSizeY; + } + // The heightmap is extended as an infinite plane at the last height + public float GetHeight(int xx, int yy) + { + int offset = 0; + // Extend the height with the height from the last row or column + if (yy >= m_sizeY) + if (xx >= m_sizeX) + offset = (m_sizeY - 1) * m_sizeX + (m_sizeX - 1); + else + offset = (m_sizeY - 1) * m_sizeX + xx; else - offset = yy * m_sizeX + xx; + if (xx >= m_sizeX) + offset = yy * m_sizeX + (m_sizeX - 1); + else + offset = yy * m_sizeX + xx; - return m_heightMap[offset]; - } - } - - // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). - // Version that handles magnification. - // Return 'true' if successfully created. - public static bool ConvertHeightmapToMesh2( BSScene physicsScene, - float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap - int magnification, // number of vertices per heighmap step - Vector3 extent, // dimensions of the output mesh - Vector3 extentBase, // base to be added to all vertices - out int indicesCountO, out int[] indicesO, - out int verticesCountO, out float[] verticesO) - { - bool ret = false; - - int indicesCount = 0; - int verticesCount = 0; - int[] indices = new int[0]; - float[] vertices = new float[0]; - - HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY); - - // The vertices dimension of the output mesh - int meshX = sizeX * magnification; - int meshY = sizeY * magnification; - // The output size of one mesh step - float meshXStep = extent.X / meshX; - float meshYStep = extent.Y / meshY; - - // Create an array of vertices that is meshX+1 by meshY+1 (note the loop - // from zero to <= meshX). The triangle indices are then generated as two triangles - // per heightmap point. There are meshX by meshY of these squares. The extra row and - // column of vertices are used to complete the triangles of the last row and column - // of the heightmap. - try - { - // Vertices for the output heightmap plus one on the side and bottom to complete triangles - int totalVertices = (meshX + 1) * (meshY + 1); - vertices = new float[totalVertices * 3]; - int totalIndices = meshX * meshY * 6; - indices = new int[totalIndices]; - - if (physicsScene != null) - physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}", - BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY), - totalVertices, totalIndices, extentBase); - - float minHeight = float.MaxValue; - // Note that sizeX+1 vertices are created since there is land between this and the next region. - // Loop through the output vertices and compute the mediun height in between the input vertices - for (int yy = 0; yy <= meshY; yy++) - { - for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times - { - float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point - int stepY = (int)offsetY; - float fractionalY = offsetY - (float)stepY; - float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point - int stepX = (int)offsetX; - float fractionalX = offsetX - (float)stepX; - - // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}", - // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY); - - // get the four corners of the heightmap square the mesh point is in - float heightUL = hmap.GetHeight(stepX , stepY ); - float heightUR = hmap.GetHeight(stepX + 1, stepY ); - float heightLL = hmap.GetHeight(stepX , stepY + 1); - float heightLR = hmap.GetHeight(stepX + 1, stepY + 1); - - // bilinear interplolation - float height = heightUL * (1 - fractionalX) * (1 - fractionalY) - + heightUR * fractionalX * (1 - fractionalY) - + heightLL * (1 - fractionalX) * fractionalY - + heightLR * fractionalX * fractionalY; - - // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}", - // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height); - - minHeight = Math.Min(minHeight, height); - - vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X; - vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y; - vertices[verticesCount + 2] = height + extentBase.Z; - verticesCount += 3; - } + return m_heightMap[offset]; } - // The number of vertices generated - verticesCount /= 3; + } - // Loop through all the heightmap squares and create indices for the two triangles for that square - for (int yy = 0; yy < meshY; yy++) + // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). + // Version that handles magnification. + // Return 'true' if successfully created. + public static bool ConvertHeightmapToMesh2( BSScene physicsScene, + float[] heightMap, int sizeX, int sizeY, // parameters of incoming heightmap + int magnification, // number of vertices per heighmap step + Vector3 extent, // dimensions of the output mesh + Vector3 extentBase, // base to be added to all vertices + out int indicesCountO, out int[] indicesO, + out int verticesCountO, out float[] verticesO) + { + bool ret = false; + + int indicesCount = 0; + int verticesCount = 0; + int[] indices = new int[0]; + float[] vertices = new float[0]; + + HeightMapGetter hmap = new HeightMapGetter(heightMap, sizeX, sizeY); + + // The vertices dimension of the output mesh + int meshX = sizeX * magnification; + int meshY = sizeY * magnification; + // The output size of one mesh step + float meshXStep = extent.X / meshX; + float meshYStep = extent.Y / meshY; + + // Create an array of vertices that is meshX+1 by meshY+1 (note the loop + // from zero to <= meshX). The triangle indices are then generated as two triangles + // per heightmap point. There are meshX by meshY of these squares. The extra row and + // column of vertices are used to complete the triangles of the last row and column + // of the heightmap. + try { - for (int xx = 0; xx < meshX; xx++) + // Vertices for the output heightmap plus one on the side and bottom to complete triangles + int totalVertices = (meshX + 1) * (meshY + 1); + vertices = new float[totalVertices * 3]; + int totalIndices = meshX * meshY * 6; + indices = new int[totalIndices]; + + if (physicsScene != null) + physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,inSize={1},outSize={2},totVert={3},totInd={4},extentBase={5}", + BSScene.DetailLogZero, new Vector2(sizeX, sizeY), new Vector2(meshX, meshY), + totalVertices, totalIndices, extentBase); + + float minHeight = float.MaxValue; + // Note that sizeX+1 vertices are created since there is land between this and the next region. + // Loop through the output vertices and compute the mediun height in between the input vertices + for (int yy = 0; yy <= meshY; yy++) { - int offset = yy * (meshX + 1) + xx; - // Each vertices is presumed to be the upper left corner of a box of two triangles - indices[indicesCount + 0] = offset; - indices[indicesCount + 1] = offset + 1; - indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column - indices[indicesCount + 3] = offset + 1; - indices[indicesCount + 4] = offset + meshX + 2; - indices[indicesCount + 5] = offset + meshX + 1; - indicesCount += 6; + for (int xx = 0; xx <= meshX; xx++) // Hint: the "<=" means we go around sizeX + 1 times + { + float offsetY = (float)yy * (float)sizeY / (float)meshY; // The Y that is closest to the mesh point + int stepY = (int)offsetY; + float fractionalY = offsetY - (float)stepY; + float offsetX = (float)xx * (float)sizeX / (float)meshX; // The X that is closest to the mesh point + int stepX = (int)offsetX; + float fractionalX = offsetX - (float)stepX; + + // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,xx={1},yy={2},offX={3},stepX={4},fractX={5},offY={6},stepY={7},fractY={8}", + // BSScene.DetailLogZero, xx, yy, offsetX, stepX, fractionalX, offsetY, stepY, fractionalY); + + // get the four corners of the heightmap square the mesh point is in + float heightUL = hmap.GetHeight(stepX , stepY ); + float heightUR = hmap.GetHeight(stepX + 1, stepY ); + float heightLL = hmap.GetHeight(stepX , stepY + 1); + float heightLR = hmap.GetHeight(stepX + 1, stepY + 1); + + // bilinear interplolation + float height = heightUL * (1 - fractionalX) * (1 - fractionalY) + + heightUR * fractionalX * (1 - fractionalY) + + heightLL * (1 - fractionalX) * fractionalY + + heightLR * fractionalX * fractionalY; + + // physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh2,heightUL={1},heightUR={2},heightLL={3},heightLR={4},heightMap={5}", + // BSScene.DetailLogZero, heightUL, heightUR, heightLL, heightLR, height); + + minHeight = Math.Min(minHeight, height); + + vertices[verticesCount + 0] = (float)xx * meshXStep + extentBase.X; + vertices[verticesCount + 1] = (float)yy * meshYStep + extentBase.Y; + vertices[verticesCount + 2] = height + extentBase.Z; + verticesCount += 3; + } } + // The number of vertices generated + verticesCount /= 3; + + // Loop through all the heightmap squares and create indices for the two triangles for that square + for (int yy = 0; yy < meshY; yy++) + { + for (int xx = 0; xx < meshX; xx++) + { + int offset = yy * (meshX + 1) + xx; + // Each vertices is presumed to be the upper left corner of a box of two triangles + indices[indicesCount + 0] = offset; + indices[indicesCount + 1] = offset + 1; + indices[indicesCount + 2] = offset + meshX + 1; // accounting for the extra column + indices[indicesCount + 3] = offset + 1; + indices[indicesCount + 4] = offset + meshX + 2; + indices[indicesCount + 5] = offset + meshX + 1; + indicesCount += 6; + } + } + + ret = true; + } + catch (Exception e) + { + if (physicsScene != null) + physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", + LogHeader, physicsScene.RegionName, extentBase, e); } - ret = true; - } - catch (Exception e) - { - if (physicsScene != null) - physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}", - LogHeader, physicsScene.RegionName, extentBase, e); - } + indicesCountO = indicesCount; + indicesO = indices; + verticesCountO = verticesCount; + verticesO = vertices; - indicesCountO = indicesCount; - indicesO = indices; - verticesCountO = verticesCount; - verticesO = vertices; - - return ret; + return ret; + } } } -} diff --git a/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs index 9f4f4a6130..8fa0ee2ce5 100755 --- a/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BulletSimData.cs @@ -32,255 +32,255 @@ using OMV = OpenMetaverse; namespace OpenSim.Region.PhysicsModule.BulletS { -// Classes to allow some type checking for the API -// These hold pointers to allocated objects in the unmanaged space. -// These classes are subclassed by the various physical implementations of -// objects. In particular, there is a version for physical instances in -// unmanaged memory ("unman") and one for in managed memory ("XNA"). + // Classes to allow some type checking for the API + // These hold pointers to allocated objects in the unmanaged space. + // These classes are subclassed by the various physical implementations of + // objects. In particular, there is a version for physical instances in + // unmanaged memory ("unman") and one for in managed memory ("XNA"). -// Currently, the instances of these classes are a reference to a -// physical representation and this has no releationship to other -// instances. Someday, refarb the usage of these classes so each instance -// refers to a particular physical instance and this class controls reference -// counts and such. This should be done along with adding BSShapes. + // Currently, the instances of these classes are a reference to a + // physical representation and this has no releationship to other + // instances. Someday, refarb the usage of these classes so each instance + // refers to a particular physical instance and this class controls reference + // counts and such. This should be done along with adding BSShapes. -public class BulletWorld -{ - public BulletWorld(uint worldId, BSScene bss) + public class BulletWorld { - worldID = worldId; - physicsScene = bss; - } - public uint worldID; - // The scene is only in here so very low level routines have a handle to print debug/error messages - public BSScene physicsScene; -} - -// An allocated Bullet btRigidBody -public class BulletBody -{ - public BulletBody(uint id) - { - ID = id; - collisionType = CollisionType.Static; - } - public uint ID; - public CollisionType collisionType; - - public virtual void Clear() { } - public virtual bool HasPhysicalBody { get { return false; } } - - // Apply the specificed collision mask into the physical world - public virtual bool ApplyCollisionMask(BSScene physicsScene) - { - // Should assert the body has been added to the physical world. - // (The collision masks are stored in the collision proxy cache which only exists for - // a collision body that is in the world.) - return physicsScene.PE.SetCollisionGroupMask(this, - BulletSimData.CollisionTypeMasks[collisionType].group, - BulletSimData.CollisionTypeMasks[collisionType].mask); + public BulletWorld(uint worldId, BSScene bss) + { + worldID = worldId; + physicsScene = bss; + } + public uint worldID; + // The scene is only in here so very low level routines have a handle to print debug/error messages + public BSScene physicsScene; } - // Used for log messages for a unique display of the memory/object allocated to this instance - public virtual string AddrString + // An allocated Bullet btRigidBody + public class BulletBody { - get { return "unknown"; } + public BulletBody(uint id) + { + ID = id; + collisionType = CollisionType.Static; + } + public uint ID; + public CollisionType collisionType; + + public virtual void Clear() { } + public virtual bool HasPhysicalBody { get { return false; } } + + // Apply the specificed collision mask into the physical world + public virtual bool ApplyCollisionMask(BSScene physicsScene) + { + // Should assert the body has been added to the physical world. + // (The collision masks are stored in the collision proxy cache which only exists for + // a collision body that is in the world.) + return physicsScene.PE.SetCollisionGroupMask(this, + BulletSimData.CollisionTypeMasks[collisionType].group, + BulletSimData.CollisionTypeMasks[collisionType].mask); + } + + // Used for log messages for a unique display of the memory/object allocated to this instance + public virtual string AddrString + { + get { return "unknown"; } + } + + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + buff.Append(""); + return buff.ToString(); + } } - public override string ToString() + // Handle to btCollisionObject - a shape that can be added to a btRidgidBody + public class BulletShape { - StringBuilder buff = new StringBuilder(); - buff.Append(""); - return buff.ToString(); + public BulletShape() + { + shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN; + shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; + isNativeShape = false; + } + public BSPhysicsShapeType shapeType; + public System.UInt64 shapeKey; + public bool isNativeShape; + + public virtual void Clear() { } + public virtual bool HasPhysicalShape { get { return false; } } + + // Make another reference to this physical object. + public virtual BulletShape Clone() { return new BulletShape(); } + + // Return 'true' if this and other refer to the same physical object + public virtual bool ReferenceSame(BulletShape xx) { return false; } + + // Used for log messages for a unique display of the memory/object allocated to this instance + public virtual string AddrString + { + get { return "unknown"; } + } + + public override string ToString() + { + StringBuilder buff = new StringBuilder(); + buff.Append(""); + return buff.ToString(); + } + } + + // An allocated Bullet btConstraint + public class BulletConstraint + { + public BulletConstraint() + { + } + public virtual void Clear() { } + public virtual bool HasPhysicalConstraint { get { return false; } } + + // Used for log messages for a unique display of the memory/object allocated to this instance + public virtual string AddrString + { + get { return "unknown"; } + } + } + + // An allocated HeightMapThing which holds various heightmap info. + // Made a class rather than a struct so there would be only one + // instance of this and C# will pass around pointers rather + // than making copies. + public class BulletHMapInfo + { + public BulletHMapInfo(uint id, float[] hm, float pSizeX, float pSizeY) { + ID = id; + heightMap = hm; + heightMapHandle = GCHandle.Alloc(heightMap, GCHandleType.Pinned); + minCoords = new OMV.Vector3(100f, 100f, 25f); + maxCoords = new OMV.Vector3(101f, 101f, 26f); + minZ = maxZ = 0f; + sizeX = pSizeX; + sizeY = pSizeY; + } + public uint ID; + public float[] heightMap; + public OMV.Vector3 terrainRegionBase; + public OMV.Vector3 minCoords; + public OMV.Vector3 maxCoords; + public float sizeX, sizeY; + public float minZ, maxZ; + public BulletShape terrainShape; + public BulletBody terrainBody; + private GCHandle heightMapHandle; + + public void Release() + { + if(heightMapHandle.IsAllocated) + heightMapHandle.Free(); + } + } + + // The general class of collsion object. + public enum CollisionType + { + Avatar, + PhantomToOthersAvatar, // An avatar that it phantom to other avatars but not to anything else + Groundplane, + Terrain, + Static, + Dynamic, + VolumeDetect, + // Linkset, // A linkset should be either Static or Dynamic + LinksetChild, + Unknown + }; + + // Hold specification of group and mask collision flags for a CollisionType + public struct CollisionTypeFilterGroup + { + public CollisionTypeFilterGroup(CollisionType t, uint g, uint m) + { + type = t; + group = g; + mask = m; + } + public CollisionType type; + public uint group; + public uint mask; + }; + + public static class BulletSimData + { + + // Map of collisionTypes to flags for collision groups and masks. + // An object's 'group' is the collison groups this object belongs to + // An object's 'filter' is the groups another object has to belong to in order to collide with me + // A collision happens if ((obj1.group & obj2.filter) != 0) || ((obj2.group & obj1.filter) != 0) + // + // As mentioned above, don't use the CollisionFilterGroups definitions directly in the code + // but, instead, use references to this dictionary. Finding and debugging + // collision flag problems will be made easier. + public static Dictionary CollisionTypeMasks + = new Dictionary() + { + { CollisionType.Avatar, + new CollisionTypeFilterGroup(CollisionType.Avatar, + (uint)CollisionFilterGroups.BCharacterGroup, + (uint)(CollisionFilterGroups.BAllGroup)) + }, + { CollisionType.PhantomToOthersAvatar, + new CollisionTypeFilterGroup(CollisionType.PhantomToOthersAvatar, + (uint)CollisionFilterGroups.BCharacterGroup, + (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BCharacterGroup)) + }, + { CollisionType.Groundplane, + new CollisionTypeFilterGroup(CollisionType.Groundplane, + (uint)CollisionFilterGroups.BGroundPlaneGroup, + // (uint)CollisionFilterGroups.BAllGroup) + (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) + }, + { CollisionType.Terrain, + new CollisionTypeFilterGroup(CollisionType.Terrain, + (uint)CollisionFilterGroups.BTerrainGroup, + (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) + }, + { CollisionType.Static, + new CollisionTypeFilterGroup(CollisionType.Static, + (uint)CollisionFilterGroups.BStaticGroup, + (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) + }, + { CollisionType.Dynamic, + new CollisionTypeFilterGroup(CollisionType.Dynamic, + (uint)CollisionFilterGroups.BSolidGroup, + (uint)(CollisionFilterGroups.BAllGroup)) + }, + { CollisionType.VolumeDetect, + new CollisionTypeFilterGroup(CollisionType.VolumeDetect, + (uint)CollisionFilterGroups.BSensorTrigger, + (uint)(~CollisionFilterGroups.BSensorTrigger)) + }, + { CollisionType.LinksetChild, + new CollisionTypeFilterGroup(CollisionType.LinksetChild, + (uint)CollisionFilterGroups.BLinksetChildGroup, + (uint)(CollisionFilterGroups.BNoneGroup)) + // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) + }, + }; + } } - -// Handle to btCollisionObject - a shape that can be added to a btRidgidBody -public class BulletShape -{ - public BulletShape() - { - shapeType = BSPhysicsShapeType.SHAPE_UNKNOWN; - shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; - isNativeShape = false; - } - public BSPhysicsShapeType shapeType; - public System.UInt64 shapeKey; - public bool isNativeShape; - - public virtual void Clear() { } - public virtual bool HasPhysicalShape { get { return false; } } - - // Make another reference to this physical object. - public virtual BulletShape Clone() { return new BulletShape(); } - - // Return 'true' if this and other refer to the same physical object - public virtual bool ReferenceSame(BulletShape xx) { return false; } - - // Used for log messages for a unique display of the memory/object allocated to this instance - public virtual string AddrString - { - get { return "unknown"; } - } - - public override string ToString() - { - StringBuilder buff = new StringBuilder(); - buff.Append(""); - return buff.ToString(); - } -} - -// An allocated Bullet btConstraint -public class BulletConstraint -{ - public BulletConstraint() - { - } - public virtual void Clear() { } - public virtual bool HasPhysicalConstraint { get { return false; } } - - // Used for log messages for a unique display of the memory/object allocated to this instance - public virtual string AddrString - { - get { return "unknown"; } - } -} - -// An allocated HeightMapThing which holds various heightmap info. -// Made a class rather than a struct so there would be only one -// instance of this and C# will pass around pointers rather -// than making copies. -public class BulletHMapInfo -{ - public BulletHMapInfo(uint id, float[] hm, float pSizeX, float pSizeY) { - ID = id; - heightMap = hm; - heightMapHandle = GCHandle.Alloc(heightMap, GCHandleType.Pinned); - minCoords = new OMV.Vector3(100f, 100f, 25f); - maxCoords = new OMV.Vector3(101f, 101f, 26f); - minZ = maxZ = 0f; - sizeX = pSizeX; - sizeY = pSizeY; - } - public uint ID; - public float[] heightMap; - public OMV.Vector3 terrainRegionBase; - public OMV.Vector3 minCoords; - public OMV.Vector3 maxCoords; - public float sizeX, sizeY; - public float minZ, maxZ; - public BulletShape terrainShape; - public BulletBody terrainBody; - private GCHandle heightMapHandle; - - public void Release() - { - if(heightMapHandle.IsAllocated) - heightMapHandle.Free(); - } -} - -// The general class of collsion object. -public enum CollisionType -{ - Avatar, - PhantomToOthersAvatar, // An avatar that it phantom to other avatars but not to anything else - Groundplane, - Terrain, - Static, - Dynamic, - VolumeDetect, - // Linkset, // A linkset should be either Static or Dynamic - LinksetChild, - Unknown -}; - -// Hold specification of group and mask collision flags for a CollisionType -public struct CollisionTypeFilterGroup -{ - public CollisionTypeFilterGroup(CollisionType t, uint g, uint m) - { - type = t; - group = g; - mask = m; - } - public CollisionType type; - public uint group; - public uint mask; -}; - -public static class BulletSimData -{ - -// Map of collisionTypes to flags for collision groups and masks. -// An object's 'group' is the collison groups this object belongs to -// An object's 'filter' is the groups another object has to belong to in order to collide with me -// A collision happens if ((obj1.group & obj2.filter) != 0) || ((obj2.group & obj1.filter) != 0) -// -// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code -// but, instead, use references to this dictionary. Finding and debugging -// collision flag problems will be made easier. -public static Dictionary CollisionTypeMasks - = new Dictionary() -{ - { CollisionType.Avatar, - new CollisionTypeFilterGroup(CollisionType.Avatar, - (uint)CollisionFilterGroups.BCharacterGroup, - (uint)(CollisionFilterGroups.BAllGroup)) - }, - { CollisionType.PhantomToOthersAvatar, - new CollisionTypeFilterGroup(CollisionType.PhantomToOthersAvatar, - (uint)CollisionFilterGroups.BCharacterGroup, - (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BCharacterGroup)) - }, - { CollisionType.Groundplane, - new CollisionTypeFilterGroup(CollisionType.Groundplane, - (uint)CollisionFilterGroups.BGroundPlaneGroup, - // (uint)CollisionFilterGroups.BAllGroup) - (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) - }, - { CollisionType.Terrain, - new CollisionTypeFilterGroup(CollisionType.Terrain, - (uint)CollisionFilterGroups.BTerrainGroup, - (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) - }, - { CollisionType.Static, - new CollisionTypeFilterGroup(CollisionType.Static, - (uint)CollisionFilterGroups.BStaticGroup, - (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) - }, - { CollisionType.Dynamic, - new CollisionTypeFilterGroup(CollisionType.Dynamic, - (uint)CollisionFilterGroups.BSolidGroup, - (uint)(CollisionFilterGroups.BAllGroup)) - }, - { CollisionType.VolumeDetect, - new CollisionTypeFilterGroup(CollisionType.VolumeDetect, - (uint)CollisionFilterGroups.BSensorTrigger, - (uint)(~CollisionFilterGroups.BSensorTrigger)) - }, - { CollisionType.LinksetChild, - new CollisionTypeFilterGroup(CollisionType.LinksetChild, - (uint)CollisionFilterGroups.BLinksetChildGroup, - (uint)(CollisionFilterGroups.BNoneGroup)) - // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) - }, -}; - -} -} diff --git a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs index cf7161adcb..7d5ca80b90 100644 --- a/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs +++ b/OpenSim/Region/PhysicsModules/ConvexDecompositionDotNet/HullUtils.cs @@ -736,8 +736,8 @@ namespace OpenSim.Region.PhysicsModules.ConvexDecompositionDotNet planeside |= vertflag[edge0.v].planetest; //if((vertflag[edge0.v].planetest & vertflag[edge1.v].planetest) == COPLANAR) { - // assert(ecop==-1); - // ecop=e; + // assert(ecop==-1); + // ecop=e; //} if (vertflag[edge0.v].planetest == (2) && vertflag[edge1.v].planetest == (2)) @@ -1398,8 +1398,8 @@ namespace OpenSim.Region.PhysicsModules.ConvexDecompositionDotNet bmin = float3.VectorMin(bmin, verts[i]); bmax = float3.VectorMax(bmax, verts[i]); } - // float diameter = magnitude(bmax-bmin); - // inflate *=diameter; // RELATIVE INFLATION + // float diameter = magnitude(bmax-bmin); + // inflate *=diameter; // RELATIVE INFLATION bmin -= new float3(inflate, inflate, inflate); bmax += new float3(inflate, inflate, inflate); for (i = 0; i < planes.Count; i++) diff --git a/OpenSim/Region/PhysicsModules/Ode/ODEApi.cs b/OpenSim/Region/PhysicsModules/Ode/ODEApi.cs index cc3077ea03..bf903ad538 100644 --- a/OpenSim/Region/PhysicsModules/Ode/ODEApi.cs +++ b/OpenSim/Region/PhysicsModules/Ode/ODEApi.cs @@ -50,7 +50,7 @@ namespace OpenSim.Region.PhysicsModule.ODE //#if dDOUBLE // don't see much use in double precision with time steps of 20ms and 10 iterations used on opensim // at least we save same memory and memory access time, FPU performance on intel usually is similar -// using dReal = System.Double; +// using dReal = System.Double; //#else using dReal = System.Single; //#endif @@ -961,7 +961,7 @@ namespace OpenSim.Region.PhysicsModule.ODE [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildByte"), SuppressUnmanagedCodeSecurity] internal static extern void GeomHeightfieldDataBuildByte(IntPtr d, IntPtr pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, - dReal scale, dReal offset, dReal thickness, int bWrap); + dReal scale, dReal offset, dReal thickness, int bWrap); [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildCallback"), SuppressUnmanagedCodeSecurity] internal static extern void GeomHeightfieldDataBuildCallback(IntPtr d, IntPtr pUserData, HeightfieldGetHeight pCallback, diff --git a/OpenSim/Region/PhysicsModules/ubOde/ODEApi.cs b/OpenSim/Region/PhysicsModules/ubOde/ODEApi.cs index a3cbf3f375..6a5e5e0d0b 100644 --- a/OpenSim/Region/PhysicsModules/ubOde/ODEApi.cs +++ b/OpenSim/Region/PhysicsModules/ubOde/ODEApi.cs @@ -49,7 +49,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde //#if dDOUBLE // don't see much use in double precision with time steps of 20ms and 10 iterations used on opensim // at least we save same memory and memory access time, FPU performance on intel usually is similar -// using dReal = System.Double; +// using dReal = System.Double; //#else using dReal = System.Single; //#endif @@ -1009,7 +1009,7 @@ namespace OpenSim.Region.PhysicsModule.ubOde [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildByte"), SuppressUnmanagedCodeSecurity] internal static extern void GeomHeightfieldDataBuildByte(IntPtr d, IntPtr pHeightData, int bCopyHeightData, dReal width, dReal depth, int widthSamples, int depthSamples, - dReal scale, dReal offset, dReal thickness, int bWrap); + dReal scale, dReal offset, dReal thickness, int bWrap); [DllImport("ode", CallingConvention = CallingConvention.Cdecl, EntryPoint = "dGeomHeightfieldDataBuildCallback"), SuppressUnmanagedCodeSecurity] internal static extern void GeomHeightfieldDataBuildCallback(IntPtr d, IntPtr pUserData, HeightfieldGetHeight pCallback, diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index 528bf7df42..c11a5a7c84 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs @@ -354,7 +354,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins float dz; // Quaternion q = SensePoint.RotationOffset; - Quaternion q = SensePoint.GetWorldRotation(); // non-attached prim Sensor *always* uses World rotation! + Quaternion q = SensePoint.GetWorldRotation(); // non-attached prim Sensor *always* uses World rotation! if (SensePoint.ParentGroup.IsAttachment) { // In attachments, rotate the sensor cone with the