2
0
Эх сурвалжийг харах

Added inspectors for all joint types

BearishSun 9 жил өмнө
parent
commit
aed25436d6

+ 279 - 0
MBansheeEditor/Inspectors/D6JointInspector.cs

@@ -0,0 +1,279 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Renders an inspector for the <see cref="D6Joint"/> component.
+    /// </summary>
+    [CustomInspector(typeof(D6Joint))]
+    public class D6JointInspector : JointInspector
+    {
+        private GUIEnumField[] motionFields = new GUIEnumField[(int) D6JointAxis.Count];
+
+        private GUIToggle linearLimitFoldout = new GUIToggle(new LocEdString("Linear limit"), EditorStyles.Foldout);
+        private LimitLinearGUI limitLinearGUI;
+        private GUIToggle twistLimitFoldout = new GUIToggle(new LocEdString("Twist limit"), EditorStyles.Foldout);
+        private LimitAngularRangeGUI limitTwistGUI;
+        private GUIToggle swingLimitFoldout = new GUIToggle(new LocEdString("Swing limit"), EditorStyles.Foldout);
+        private LimitConeRangeGUI limitSwingGUI;
+
+        private GUIToggle driveFoldout = new GUIToggle(new LocEdString("Drive"), EditorStyles.Foldout);
+        private D6JointDriveGUI[] drivesGUI = new D6JointDriveGUI[(int)D6JointDriveType.Count];
+        private GUIVector3Field drivePositionField = new GUIVector3Field(new LocEdString("Drive position"));
+        private GUIVector3Field driveRotationField = new GUIVector3Field(new LocEdString("Drive rotation"));
+        private GUIVector3Field driveLinVelocityField = new GUIVector3Field(new LocEdString("Drive linear velocity"));
+        private GUIVector3Field driveAngVelocityField = new GUIVector3Field(new LocEdString("Drive angular velocity"));
+
+        private GUILayoutX linearLimitLayout;
+        private GUILayoutX twistLimitLayout;
+        private GUILayoutX swingLimitLayout;
+        private GUILayoutX driveLayout;
+
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            D6Joint joint = InspectedObject as D6Joint;
+
+            if (joint != null)
+                BuildGUI(joint);
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            D6Joint joint = InspectedObject as D6Joint;
+            if (joint == null)
+                return InspectableState.NotModified;
+
+            Refresh(joint);
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Creates GUI elements for fields specific to the spherical joint.
+        /// </summary>
+        protected void BuildGUI(D6Joint joint)
+        {
+            for (int i = 0; i < (int) D6JointAxis.Count; i++)
+            {
+                D6JointAxis axis = (D6JointAxis) i;
+                string entryName = Enum.GetName(typeof (D6JointAxis), axis);
+
+                motionFields[i] = new GUIEnumField(typeof (D6JointMotion), new LocEdString(entryName));
+                motionFields[i].OnSelectionChanged += x =>
+                {
+                    joint.SetMotion(axis, (D6JointMotion)x);
+
+                    MarkAsModified();
+                    ConfirmModify();
+                };
+            }
+
+            linearLimitFoldout.OnToggled += x =>
+            {
+                linearLimitLayout.Active = x;
+                Persistent.SetBool("linearLimit_Expanded", x);
+            };
+
+            twistLimitFoldout.OnToggled += x =>
+            {
+                twistLimitLayout.Active = x;
+                Persistent.SetBool("twistLimit_Expanded", x);
+            };
+
+            swingLimitFoldout.OnToggled += x =>
+            {
+                swingLimitLayout.Active = x;
+                Persistent.SetBool("swingLimit_Expanded", x);
+            };
+
+            driveFoldout.OnToggled += x =>
+            {
+                driveLayout.Active = x;
+                Persistent.SetBool("drive_Expanded", x);
+            };
+
+            drivePositionField.OnChanged += x => { joint.DrivePosition = x; MarkAsModified(); };
+            drivePositionField.OnFocusLost += ConfirmModify;
+            drivePositionField.OnConfirmed += ConfirmModify;
+
+            driveRotationField.OnChanged += x => { joint.DriveRotation = Quaternion.FromEuler(x); MarkAsModified(); };
+            driveRotationField.OnFocusLost += ConfirmModify;
+            driveRotationField.OnConfirmed += ConfirmModify;
+
+            driveLinVelocityField.OnChanged += x => { joint.DriveLinearVelocity = x; MarkAsModified(); };
+            driveLinVelocityField.OnFocusLost += ConfirmModify;
+            driveLinVelocityField.OnConfirmed += ConfirmModify;
+
+            driveAngVelocityField.OnChanged += x => { joint.DriveAngularVelocity = x; MarkAsModified(); };
+            driveAngVelocityField.OnFocusLost += ConfirmModify;
+            driveAngVelocityField.OnConfirmed += ConfirmModify;
+
+            for (int i = 0; i < (int) D6JointAxis.Count; i++)
+                Layout.AddElement(motionFields[i]);
+
+            Layout.AddElement(linearLimitFoldout);
+            linearLimitLayout = Layout.AddLayoutX();
+            {
+                linearLimitLayout.AddSpace(10);
+                GUILayoutY linearLimitContentsLayout = linearLimitLayout.AddLayoutY();
+                limitLinearGUI = new LimitLinearGUI(joint.LimitLinear, linearLimitContentsLayout, Persistent);
+            }
+
+            Layout.AddElement(twistLimitFoldout);
+            twistLimitLayout = Layout.AddLayoutX();
+            {
+                twistLimitLayout.AddSpace(10);
+                GUILayoutY twistLimitContentsLayout = twistLimitLayout.AddLayoutY();
+                limitTwistGUI = new LimitAngularRangeGUI(joint.LimitTwist, twistLimitContentsLayout, Persistent);
+            }
+
+            Layout.AddElement(swingLimitFoldout);
+            swingLimitLayout = Layout.AddLayoutX();
+            {
+                swingLimitLayout.AddSpace(10);
+                GUILayoutY swingLimitContentsLayout = swingLimitLayout.AddLayoutY();
+                limitSwingGUI = new LimitConeRangeGUI(joint.LimitSwing, swingLimitContentsLayout, Persistent);
+            }
+
+            Layout.AddElement(driveFoldout);
+            driveLayout = Layout.AddLayoutX();
+            {
+                driveLayout.AddSpace(10);
+                GUILayoutY driveContentsLayout = driveLayout.AddLayoutY();
+
+                for (int i = 0; i < (int) D6JointDriveType.Count; i++)
+                {
+                    D6JointDriveType type = (D6JointDriveType)i;
+
+                    drivesGUI[i] = new D6JointDriveGUI(joint.GetDrive(type), driveContentsLayout);
+                    drivesGUI[i].OnChanged += x => { joint.SetDrive(type, new D6JointDrive(x)); MarkAsModified(); };
+                    drivesGUI[i].OnConfirmed += ConfirmModify;
+                }
+
+                driveContentsLayout.AddElement(drivePositionField);
+                driveContentsLayout.AddElement(driveRotationField);
+                driveContentsLayout.AddElement(driveLinVelocityField);
+                driveContentsLayout.AddElement(driveAngVelocityField);
+            }
+
+            linearLimitLayout.Active = Persistent.GetBool("linearLimit_Expanded");
+            twistLimitLayout.Active = Persistent.GetBool("twistLimit_Expanded");
+            swingLimitLayout.Active = Persistent.GetBool("swingLimit_Expanded");
+            driveLayout.Active = Persistent.GetBool("drive_Expanded");
+
+            base.BuildGUI(joint);
+        }
+
+        /// <summary>
+        /// Updates all GUI elements from current values in the joint.
+        /// </summary>
+        /// <param name="joint">Joint to update the GUI from.</param>
+        protected void Refresh(D6Joint joint)
+        {
+            for (int i = 0; i < (int) D6JointAxis.Count; i++)
+                motionFields[i].Value = (ulong)joint.GetMotion((D6JointAxis) i);
+
+            limitLinearGUI.Limit = joint.LimitLinear;
+            limitTwistGUI.Limit = joint.LimitTwist;
+            limitSwingGUI.Limit = joint.LimitSwing;
+
+            for (int i = 0; i < (int) D6JointDriveType.Count; i++)
+                drivesGUI[i].Drive = joint.GetDrive((D6JointDriveType) i);
+
+            drivePositionField.Value = joint.DrivePosition;
+            driveRotationField.Value = joint.DriveRotation.ToEuler();
+            driveLinVelocityField.Value = joint.DriveLinearVelocity;
+            driveAngVelocityField.Value = joint.DriveAngularVelocity;
+
+            base.Refresh(joint);
+        }
+    }
+
+    /// <summary>
+    /// Draws GUI elements for inspecting an <see cref="D6JointDrive"/> object.
+    /// </summary>
+    internal class D6JointDriveGUI
+    {
+        private D6JointDriveData driveData;
+
+        private GUIFloatField stiffnessField = new GUIFloatField(new LocEdString("Stiffness"));
+        private GUIFloatField dampingField = new GUIFloatField(new LocEdString("Damping"));
+        private GUIFloatField forceLimitField = new GUIFloatField(new LocEdString("Force limit"));
+        private GUIToggleField accelerationField = new GUIToggleField(new LocEdString("Acceleration"));
+
+        public Action<D6JointDriveData> OnChanged;
+        public Action OnConfirmed;
+
+        /// <summary>
+        /// Current drive properties.
+        /// </summary>
+        public D6JointDrive Drive
+        {
+            set
+            {
+                driveData = value.Data;
+
+                stiffnessField.Value = driveData.stiffness;
+                dampingField.Value = driveData.damping;
+                forceLimitField.Value = driveData.forceLimit;
+                accelerationField.Value = driveData.acceleration;
+            }
+        }
+
+        /// <summary>
+        /// Constructs a new set of GUI elements for inspecting the drive object.
+        /// </summary>
+        /// <param name="drive">Initial values to assign to the GUI elements.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        public D6JointDriveGUI(D6JointDrive drive, GUILayout layout)
+        {
+            driveData = drive.Data;
+
+            stiffnessField.OnChanged += x => { driveData.stiffness = x; MarkAsModified(); };
+            stiffnessField.OnFocusLost += ConfirmModify;
+            stiffnessField.OnConfirmed += ConfirmModify;
+
+            dampingField.OnChanged += x => { driveData.damping = x; MarkAsModified(); };
+            dampingField.OnFocusLost += ConfirmModify;
+            dampingField.OnConfirmed += ConfirmModify;
+
+            forceLimitField.OnChanged += x => { driveData.forceLimit = x; MarkAsModified(); };
+            forceLimitField.OnFocusLost += ConfirmModify;
+            forceLimitField.OnConfirmed += ConfirmModify;
+
+            accelerationField.OnChanged += x => { driveData.acceleration = x; MarkAsModified(); ConfirmModify(); };
+
+            layout.AddElement(stiffnessField);
+            layout.AddElement(dampingField);
+            layout.AddElement(forceLimitField);
+            layout.AddElement(accelerationField);
+        }
+
+        /// <summary>
+        /// Marks the contents of the inspector as modified.
+        /// </summary>
+        private void MarkAsModified()
+        {
+            if (OnChanged != null)
+                OnChanged(driveData);
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications.
+        /// </summary>
+        private void ConfirmModify()
+        {
+            if (OnConfirmed != null)
+                OnConfirmed();
+        }
+    }
+}

+ 157 - 0
MBansheeEditor/Inspectors/DistanceJointInspector.cs

@@ -0,0 +1,157 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Renders an inspector for the <see cref="DistanceJoint"/> component.
+    /// </summary>
+    [CustomInspector(typeof(DistanceJoint))]
+    public class DistanceJointInspector : JointInspector
+    {
+        private GUIToggleField enableMinLimitField = new GUIToggleField(new LocEdString("Enable minimum limit"));
+        private GUIFloatField minLimitField = new GUIFloatField("Minimum distance");
+        private GUIToggleField enableMaxLimitField = new GUIToggleField(new LocEdString("Enable maximum limit"));
+        private GUIFloatField maxLimitField = new GUIFloatField("Maximum maximum");
+        private GUIFloatField toleranceField = new GUIFloatField("Tolerance");
+        private GUIToggleField enableSpringField = new GUIToggleField(new LocEdString("Enable spring"));
+        private SpringGUI springGUI;
+
+        private GUILayoutX springLayout;
+
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            DistanceJoint joint = InspectedObject as DistanceJoint;
+
+            if (joint != null)
+                BuildGUI(joint);
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            DistanceJoint joint = InspectedObject as DistanceJoint;
+            if (joint == null)
+                return InspectableState.NotModified;
+
+            Refresh(joint);
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Creates GUI elements for fields specific to the distance joint.
+        /// </summary>
+        protected void BuildGUI(DistanceJoint joint)
+        {
+            enableMinLimitField.OnChanged += x =>
+            {
+                joint.EnableMinDistanceLimit = x;
+                MarkAsModified();
+                ConfirmModify();
+
+                minLimitField.Active = x;
+            };
+
+            minLimitField.OnChanged += x => { joint.MinDistance = x; MarkAsModified(); };
+            minLimitField.OnFocusLost += ConfirmModify;
+            minLimitField.OnConfirmed += ConfirmModify;
+
+            enableMaxLimitField.OnChanged += x =>
+            {
+                joint.EnableMaxDistanceLimit = x;
+                MarkAsModified();
+                ConfirmModify();
+
+                maxLimitField.Active = x;
+            };
+
+            maxLimitField.OnChanged += x => { joint.MaxDistance = x; MarkAsModified(); };
+            maxLimitField.OnFocusLost += ConfirmModify;
+            maxLimitField.OnConfirmed += ConfirmModify;
+
+            toleranceField.OnChanged += x => { joint.Tolerance = x; MarkAsModified(); };
+            toleranceField.OnFocusLost += ConfirmModify;
+            toleranceField.OnConfirmed += ConfirmModify;
+
+            enableSpringField.OnChanged += x =>
+            {
+                joint.EnableSpring = x;
+                MarkAsModified();
+                ConfirmModify();
+
+                springLayout.Active = x;
+            };
+
+            Layout.AddElement(enableMinLimitField);
+            GUILayoutX minLimitLayout = Layout.AddLayoutX();
+            {
+                minLimitLayout.AddSpace(10);
+                minLimitLayout.AddElement(minLimitField);
+            }
+
+            Layout.AddElement(enableMaxLimitField);
+            GUILayoutX maxLimitLayout = Layout.AddLayoutX();
+            {
+                maxLimitLayout.AddSpace(10);
+                maxLimitLayout.AddElement(maxLimitField);
+            }
+
+            Layout.AddElement(toleranceField);
+            Layout.AddElement(enableSpringField);
+            springLayout = Layout.AddLayoutX();
+            {
+                springLayout.AddSpace(10);
+                springGUI = new SpringGUI(joint.Spring, springLayout);
+                springGUI.OnChanged += x => { joint.Spring = x; MarkAsModified(); };
+                springGUI.OnConfirmed += ConfirmModify;
+            }
+
+            minLimitField.Active = joint.EnableMinDistanceLimit;
+            maxLimitField.Active = joint.EnableMaxDistanceLimit;
+            springLayout.Active = joint.EnableSpring;
+
+            base.BuildGUI(joint);
+        }
+
+        /// <summary>
+        /// Updates all GUI elements from current values in the joint.
+        /// </summary>
+        /// <param name="joint">Joint to update the GUI from.</param>
+        protected void Refresh(DistanceJoint joint)
+        {
+            if (enableMinLimitField.Value != joint.EnableMinDistanceLimit)
+            {
+                enableMinLimitField.Value = joint.EnableMinDistanceLimit;
+                minLimitField.Active = joint.EnableMinDistanceLimit;
+            }
+
+            minLimitField.Value = joint.MinDistance;
+
+            if (enableMaxLimitField.Value != joint.EnableMaxDistanceLimit)
+            {
+                enableMaxLimitField.Value = joint.EnableMaxDistanceLimit;
+                maxLimitField.Active = joint.EnableMaxDistanceLimit;
+            }
+
+            maxLimitField.Value = joint.MaxDistance;
+            toleranceField.Value = joint.Tolerance;
+
+            if (enableSpringField.Value != joint.EnableSpring)
+            {
+                enableSpringField.Value = joint.EnableSpring;
+                springLayout.Active = joint.EnableSpring;
+            }
+
+            springGUI.Spring = joint.Spring;
+
+            base.Refresh(joint);
+        }
+    }
+}

+ 38 - 0
MBansheeEditor/Inspectors/FixedJointInspector.cs

@@ -0,0 +1,38 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Renders an inspector for the <see cref="FixedJoint"/> component.
+    /// </summary>
+    [CustomInspector(typeof(FixedJoint))]
+    public class FixedJointInspector : JointInspector
+    {
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            FixedJoint joint = InspectedObject as FixedJoint;
+
+            if (joint != null)
+                BuildGUI(joint);
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            FixedJoint joint = InspectedObject as FixedJoint;
+            if (joint == null)
+                return InspectableState.NotModified;
+
+            Refresh(joint);
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+    }
+}

+ 196 - 0
MBansheeEditor/Inspectors/HingeJointInspector.cs

@@ -0,0 +1,196 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Renders an inspector for the <see cref="HingeJoint"/> component.
+    /// </summary>
+    [CustomInspector(typeof(HingeJoint))]
+    public class HingeJointInspector : JointInspector
+    {
+        private GUIToggleField enableLimitField = new GUIToggleField(new LocEdString("Enable limit"));
+        private LimitAngularRangeGUI limitGUI;
+
+        private GUIToggleField enableDriveField = new GUIToggleField(new LocEdString("Enable drive"));
+        private GUIFloatField speedField = new GUIFloatField(new LocEdString("Speed"));
+        private GUIFloatField forceLimitField = new GUIFloatField(new LocEdString("Force limit"));
+        private GUIFloatField gearRatioField = new GUIFloatField(new LocEdString("Gear ratio"));
+        private GUIToggleField freeSpinField = new GUIToggleField(new LocEdString("Free spin"));
+
+        private GUILayoutX limitLayout;
+        private GUILayoutX driveLayout;
+
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            HingeJoint joint = InspectedObject as HingeJoint;
+
+            if (joint != null)
+                BuildGUI(joint);
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            HingeJoint joint = InspectedObject as HingeJoint;
+            if (joint == null)
+                return InspectableState.NotModified;
+
+            Refresh(joint);
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Creates GUI elements for fields specific to the hinge joint.
+        /// </summary>
+        protected void BuildGUI(HingeJoint joint)
+        {
+            enableLimitField.OnChanged += x =>
+            {
+                joint.EnableLimit = x;
+                MarkAsModified();
+                ConfirmModify();
+
+                ToggleLimitFields(x);
+            };
+            
+            enableDriveField.OnChanged += x =>
+            {
+                joint.EnableDrive = x;
+                MarkAsModified();
+                ConfirmModify();
+
+                ToggleDriveFields(x);
+            };
+
+            speedField.OnChanged += x =>
+            {
+                HingeJointDriveData driveData = joint.Drive.Data;
+                driveData.speed = x;
+                joint.Drive = new HingeJointDrive(driveData);
+
+                MarkAsModified();
+            };
+            speedField.OnFocusLost += ConfirmModify;
+            speedField.OnConfirmed += ConfirmModify;
+
+            forceLimitField.OnChanged += x =>
+            {
+                HingeJointDriveData driveData = joint.Drive.Data;
+                driveData.forceLimit = x;
+                joint.Drive = new HingeJointDrive(driveData);
+
+                MarkAsModified();
+            };
+            forceLimitField.OnFocusLost += ConfirmModify;
+            forceLimitField.OnConfirmed += ConfirmModify;
+
+            gearRatioField.OnChanged += x =>
+            {
+                HingeJointDriveData driveData = joint.Drive.Data;
+                driveData.gearRatio = x;
+                joint.Drive = new HingeJointDrive(driveData);
+
+                MarkAsModified();
+            };
+            gearRatioField.OnFocusLost += ConfirmModify;
+            gearRatioField.OnConfirmed += ConfirmModify;
+
+            freeSpinField.OnChanged += x =>
+            {
+                HingeJointDriveData driveData = joint.Drive.Data;
+                driveData.freeSpin = x;
+                joint.Drive = new HingeJointDrive(driveData);
+
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            Layout.AddElement(enableLimitField);
+            limitLayout = Layout.AddLayoutX();
+            {
+                limitLayout.AddSpace(10);
+
+                GUILayoutY limitContentsLayout = limitLayout.AddLayoutY();
+                limitGUI = new LimitAngularRangeGUI(joint.Limit, limitContentsLayout, Persistent);
+                limitGUI.OnChanged += (x, y) =>
+                {
+                    joint.Limit = new LimitAngularRange(x, y);
+
+                    MarkAsModified();
+                };
+                limitGUI.OnConfirmed += ConfirmModify;
+            }
+
+            Layout.AddElement(enableDriveField);
+            driveLayout = Layout.AddLayoutX();
+            {
+                driveLayout.AddSpace(10);
+
+                GUILayoutY driveContentsLayout = driveLayout.AddLayoutY();
+                driveContentsLayout.AddElement(speedField);
+                driveContentsLayout.AddElement(forceLimitField);
+                driveContentsLayout.AddElement(gearRatioField);
+                driveContentsLayout.AddElement(freeSpinField);
+            }
+
+            ToggleLimitFields(joint.EnableLimit);
+            ToggleDriveFields(joint.EnableDrive);
+
+            base.BuildGUI(joint);
+        }
+
+        /// <summary>
+        /// Updates all GUI elements from current values in the joint.
+        /// </summary>
+        /// <param name="joint">Joint to update the GUI from.</param>
+        protected void Refresh(HingeJoint joint)
+        {
+            if (enableLimitField.Value != joint.EnableLimit)
+            {
+                enableLimitField.Value = joint.EnableLimit;
+                ToggleLimitFields(joint.EnableLimit);
+            }
+
+            limitGUI.Limit = joint.Limit;
+
+            if (enableDriveField.Value != joint.EnableDrive)
+            {
+                enableDriveField.Value = joint.EnableDrive;
+                ToggleDriveFields(joint.EnableDrive);
+            }
+
+            speedField.Value = joint.Drive.Speed;
+            forceLimitField.Value = joint.Drive.ForceLimit;
+            gearRatioField.Value = joint.Drive.GearRatio;
+            freeSpinField.Value = joint.Drive.FreeSpin;
+
+            base.Refresh(joint);
+        }
+
+        /// <summary>
+        /// Hides or shows limit property GUI elements.
+        /// </summary>
+        /// <param name="enable">True to show, false to hide.</param>
+        private void ToggleLimitFields(bool enable)
+        {
+            limitLayout.Active = enable;
+        }
+
+        /// <summary>
+        /// Hides or shows drive property GUI elements.
+        /// </summary>
+        /// <param name="enable">True to show, false to hide.</param>
+        private void ToggleDriveFields(bool enable)
+        {
+            driveLayout.Active = enable;
+        }
+    }
+}

+ 92 - 0
MBansheeEditor/Inspectors/JointInspector.cs

@@ -0,0 +1,92 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Renders common inspector elements for all <see cref="Joint"/> components.
+    /// </summary>
+    public abstract class JointInspector : Inspector
+    {
+        private GUIGameObjectField bodyAField = new GUIGameObjectField(typeof(Rigidbody), new LocEdString("Body A"));
+        private GUIVector3Field bodyAOffsetField = new GUIVector3Field(new LocEdString("Body A offset"));
+
+        private GUIGameObjectField bodyBField = new GUIGameObjectField(typeof(Rigidbody), new LocEdString("Body B"));
+        private GUIVector3Field bodyBOffsetField = new GUIVector3Field(new LocEdString("Body B offset"));
+
+        private GUIFloatField breakForceField = new GUIFloatField(new LocEdString("Break force"));
+        private GUIFloatField breakTorqueField = new GUIFloatField(new LocEdString("Break torque"));
+        private GUIToggleField collisionField = new GUIToggleField(new LocEdString("Enable collision"));
+        
+        protected InspectableState modifyState;
+
+        /// <summary>
+        /// Updates all GUI elements from current values in the joint.
+        /// </summary>
+        /// <param name="joint">Joint to update the GUI from.</param>
+        protected virtual void Refresh(Joint joint)
+        {
+            bodyAField.Value = joint.GetRigidbody(JointBody.A);
+            bodyAOffsetField.Value = joint.GetPosition(JointBody.A);
+
+            bodyBField.Value = joint.GetRigidbody(JointBody.B);
+            bodyBOffsetField.Value = joint.GetPosition(JointBody.B);
+
+            breakForceField.Value = joint.BreakForce;
+            breakTorqueField.Value = joint.BreakTorque;
+            collisionField.Value = joint.EnableCollision;
+        }
+
+        /// <summary>
+        /// Creates GUI elements for fields common to all joints.
+        /// </summary>
+        protected virtual void BuildGUI(Joint joint)
+        {
+            bodyAField.OnChanged += x => { joint.SetRigidbody(JointBody.A, (Rigidbody)x); MarkAsModified(); ConfirmModify(); };
+            bodyAOffsetField.OnChanged += x => { joint.SetPosition(JointBody.A, x); MarkAsModified(); };
+            bodyAOffsetField.OnFocusLost += ConfirmModify;
+            bodyAOffsetField.OnConfirmed += ConfirmModify;
+
+            bodyBField.OnChanged += x => { joint.SetRigidbody(JointBody.B, (Rigidbody)x); MarkAsModified(); ConfirmModify(); };
+            bodyBOffsetField.OnChanged += x => { joint.SetPosition(JointBody.B, x); MarkAsModified(); };
+            bodyBOffsetField.OnFocusLost += ConfirmModify;
+            bodyBOffsetField.OnConfirmed += ConfirmModify;
+
+            breakForceField.OnChanged += x => { joint.BreakForce = x; MarkAsModified(); };
+            breakForceField.OnFocusLost += ConfirmModify;
+            breakForceField.OnConfirmed += ConfirmModify;
+
+            breakTorqueField.OnChanged += x => { joint.BreakTorque = x; MarkAsModified(); };
+            breakTorqueField.OnFocusLost += ConfirmModify;
+            breakTorqueField.OnConfirmed += ConfirmModify;
+
+            collisionField.OnChanged += x => { joint.EnableCollision = x; MarkAsModified(); ConfirmModify(); };
+            
+            Layout.AddElement(bodyAField);
+            Layout.AddElement(bodyAOffsetField);
+            Layout.AddElement(bodyBField);
+            Layout.AddElement(bodyBOffsetField);
+            Layout.AddElement(breakForceField);
+            Layout.AddElement(breakTorqueField);
+            Layout.AddElement(collisionField);
+        }
+
+        /// <summary>
+        /// Marks the contents of the inspector as modified.
+        /// </summary>
+        protected void MarkAsModified()
+        {
+            modifyState |= InspectableState.ModifyInProgress;
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications.
+        /// </summary>
+        protected void ConfirmModify()
+        {
+            if (modifyState.HasFlag(InspectableState.ModifyInProgress))
+                modifyState |= InspectableState.Modified;
+        }
+    }
+}

+ 492 - 0
MBansheeEditor/Inspectors/LimitInspectors.cs

@@ -0,0 +1,492 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Draws GUI elements for inspecting an <see cref="Spring"/> object.
+    /// </summary>
+    internal class SpringGUI
+    {
+        private Spring spring;
+
+        private GUIFloatField stiffnessField = new GUIFloatField(new LocEdString("Stiffness"));
+        private GUIFloatField dampingField = new GUIFloatField(new LocEdString("Damping"));
+
+        public Action<Spring> OnChanged;
+        public Action OnConfirmed;
+
+        /// <summary>
+        /// Current value of the spring object.
+        /// </summary>
+        public Spring Spring
+        {
+            get { return spring; }
+            set
+            {
+                spring = value;
+
+                stiffnessField.Value = value.stiffness;
+                dampingField.Value = value.damping;
+            }
+        }
+
+        /// <summary>
+        /// Constructs a new set of GUI elements for inspecting the spring object.
+        /// </summary>
+        /// <param name="spring">Initial values to assign to the GUI elements.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        public SpringGUI(Spring spring, GUILayout layout)
+        {
+            this.spring = spring;
+
+            stiffnessField.OnChanged += x => { spring.stiffness = x; MarkAsModified(); };
+            stiffnessField.OnFocusLost += ConfirmModify;
+            stiffnessField.OnConfirmed += ConfirmModify;
+
+            dampingField.OnChanged += x => { spring.damping = x; MarkAsModified(); };
+            dampingField.OnFocusLost += ConfirmModify;
+            dampingField.OnConfirmed += ConfirmModify;
+
+            layout.AddElement(stiffnessField);
+            layout.AddElement(dampingField);
+        }
+
+        /// <summary>
+        /// Marks the contents of the inspector as modified.
+        /// </summary>
+        private void MarkAsModified()
+        {
+            if (OnChanged != null)
+                OnChanged(spring);
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications.
+        /// </summary>
+        private void ConfirmModify()
+        {
+            if (OnConfirmed != null)
+                OnConfirmed();
+        }
+    }
+
+    /// <summary>
+    /// Draws GUI elements for inspecting an <see cref="LimitCommon"/> object.
+    /// </summary>
+    internal class LimitCommonGUI
+    {
+        private LimitCommonData limitData;
+        private SerializableProperties properties;
+        private string prefix;
+
+        private GUIToggle hardFoldout = new GUIToggle(new LocEdString("Hard"), EditorStyles.Foldout);
+        private GUIFloatField contactDistanceField = new GUIFloatField(new LocEdString("Contact distance"));
+        private GUIToggle softFoldout = new GUIToggle(new LocEdString("Soft"), EditorStyles.Foldout);
+        private GUISliderField restitutionField = new GUISliderField(0, 1, new LocEdString("Restitution"));
+        private GUIToggle springFoldout = new GUIToggle(new LocEdString("Spring"), EditorStyles.Foldout);
+        private SpringGUI springGUI;
+
+        private GUILayoutX hardLimitLayout;
+        private GUILayoutX softLimitLayout;
+        private GUILayoutX springLayout;
+
+        public Action<LimitCommonData> OnChanged;
+        public Action OnConfirmed;
+
+        /// <summary>
+        /// Current limit properties.
+        /// </summary>
+        public LimitCommonData LimitData
+        {
+            get { return limitData; }
+            set
+            {
+                limitData = value;
+
+                contactDistanceField.Value = value.contactDist;
+                restitutionField.Value = value.restitution;
+                springGUI.Spring = value.spring;
+            }
+        }
+
+        /// <summary>
+        /// Constructs a new set of GUI elements for inspecting the limit object.
+        /// </summary>
+        /// <param name="prefix">Prefix that identifies the exact type of the limit type.</param>
+        /// <param name="limitData">Initial values to assign to the GUI elements.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        /// <param name="properties">A set of properties that are persisted by the parent inspector. Used for saving state.
+        ///                          </param>
+        public LimitCommonGUI(string prefix, LimitCommonData limitData, GUILayout layout, SerializableProperties properties)
+        {
+            this.limitData = limitData;
+            this.properties = properties;
+            this.prefix = prefix;
+
+            hardFoldout.OnToggled += x =>
+            {
+                properties.SetBool(prefix + "_hardLimit_Expanded", x);
+                ToggleLimitFields();
+            };
+
+            contactDistanceField.OnChanged += x => { limitData.contactDist = x; MarkAsModified(); };
+            contactDistanceField.OnFocusLost += ConfirmModify;
+            contactDistanceField.OnConfirmed += ConfirmModify;
+
+            softFoldout.OnToggled += x =>
+            {
+                properties.SetBool(prefix + "_softLimit_Expanded", x);
+                ToggleLimitFields();
+            };
+
+            restitutionField.OnChanged += x => { limitData.restitution = x; MarkAsModified(); };
+            restitutionField.OnFocusLost += ConfirmModify;
+
+            springFoldout.OnToggled += x =>
+            {
+                properties.SetBool(prefix + "_spring_Expanded", x);
+                ToggleLimitFields();
+            };
+
+            hardLimitLayout = layout.AddLayoutX();
+            {
+                hardLimitLayout.AddSpace(10);
+
+                GUILayoutY hardLimitContentsLayout = hardLimitLayout.AddLayoutY();
+                hardLimitContentsLayout.AddElement(contactDistanceField);
+            }
+
+            softLimitLayout = layout.AddLayoutX();
+            layout.AddElement(softFoldout);
+            {
+                softLimitLayout.AddSpace(10);
+
+                GUILayoutY softLimitContentsLayout = softLimitLayout.AddLayoutY();
+                softLimitContentsLayout.AddElement(restitutionField);
+                softLimitContentsLayout.AddElement(springFoldout);
+                springLayout = softLimitContentsLayout.AddLayoutX();
+                {
+                    springLayout.AddSpace(10);
+
+                    GUILayoutY springContentsLayout = springLayout.AddLayoutY();
+                    springGUI = new SpringGUI(limitData.spring, springContentsLayout);
+                    springGUI.OnChanged += x => { limitData.spring = x; MarkAsModified(); };
+                    springGUI.OnConfirmed += ConfirmModify;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Marks the contents of the inspector as modified.
+        /// </summary>
+        private void MarkAsModified()
+        {
+            if (OnChanged != null)
+                OnChanged(limitData);
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications.
+        /// </summary>
+        private void ConfirmModify()
+        {
+            if (OnConfirmed != null)
+                OnConfirmed();
+        }
+
+        /// <summary>
+        /// Hides or shows limit property GUI elements depending on set properties.
+        /// </summary>
+        private void ToggleLimitFields()
+        {
+            hardLimitLayout.Active = properties.GetBool(prefix + "_hardLimit_Expanded");
+            softLimitLayout.Active = properties.GetBool(prefix + "_softLimit_Expanded");
+            springLayout.Active = properties.GetBool(prefix + "_spring_Expanded");
+        }
+    }
+
+    /// <summary>
+    /// Draws GUI elements for inspecting an <see cref="LimitLinear"/> object.
+    /// </summary>
+    internal class LimitLinearGUI
+    {
+        private LimitLinearData limitData;
+
+        private GUIFloatField limitExtentField = new GUIFloatField(new LocEdString("Extent"));
+        private LimitCommonGUI limitCommonGUI;
+
+        public Action<LimitLinearData, LimitCommonData> OnChanged;
+        public Action OnConfirmed;
+
+        /// <summary>
+        /// Current limit properties.
+        /// </summary>
+        public LimitLinear Limit
+        {
+            set
+            {
+                limitData = value.Data;
+
+                limitExtentField.Value = limitData.extent;
+                limitCommonGUI.LimitData = value.CommonData;
+            }
+        }
+
+        /// <summary>
+        /// Constructs a new set of GUI elements for inspecting the limit object.
+        /// </summary>
+        /// <param name="limit">Initial values to assign to the GUI elements.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        /// <param name="properties">A set of properties that are persisted by the parent inspector. Used for saving state.
+        ///                          </param>
+        public LimitLinearGUI(LimitLinear limit, GUILayout layout, SerializableProperties properties)
+        {
+            this.limitData = limit.Data;
+
+            limitExtentField.OnChanged += x => { limitData.extent = x; MarkAsModified(); };
+            limitExtentField.OnFocusLost += ConfirmModify;
+
+            layout.AddElement(limitExtentField);
+            limitCommonGUI = new LimitCommonGUI("linear", limit.CommonData, layout, properties);
+            limitCommonGUI.OnChanged += x => MarkAsModified();
+            limitCommonGUI.OnConfirmed += ConfirmModify;
+        }
+
+        /// <summary>
+        /// Marks the contents of the inspector as modified.
+        /// </summary>
+        private void MarkAsModified()
+        {
+            if (OnChanged != null)
+                OnChanged(limitData, limitCommonGUI.LimitData);
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications.
+        /// </summary>
+        private void ConfirmModify()
+        {
+            if (OnConfirmed != null)
+                OnConfirmed();
+        }
+    }
+
+    /// <summary>
+    /// Draws GUI elements for inspecting an <see cref="LimitLinearRange"/> object.
+    /// </summary>
+    internal class LimitLinearRangeGUI
+    {
+        private LimitLinearRangeData limitData;
+
+        private GUIFloatField limitLowerField = new GUIFloatField(new LocEdString("Lower"));
+        private GUIFloatField limitUpperField = new GUIFloatField(new LocEdString("Upper"));
+        private LimitCommonGUI limitCommonGUI;
+
+        public Action<LimitLinearRangeData, LimitCommonData> OnChanged;
+        public Action OnConfirmed;
+
+        /// <summary>
+        /// Current limit properties.
+        /// </summary>
+        public LimitLinearRange Limit
+        {
+            set
+            {
+                limitData = value.Data;
+
+                limitLowerField.Value = limitData.lower;
+                limitUpperField.Value = limitData.upper;
+                limitCommonGUI.LimitData = value.CommonData;
+            }
+        }
+
+        /// <summary>
+        /// Constructs a new set of GUI elements for inspecting the limit object.
+        /// </summary>
+        /// <param name="limit">Initial values to assign to the GUI elements.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        /// <param name="properties">A set of properties that are persisted by the parent inspector. Used for saving state.
+        ///                          </param>
+        public LimitLinearRangeGUI(LimitLinearRange limit, GUILayout layout, SerializableProperties properties)
+        {
+            this.limitData = limit.Data;
+
+            limitLowerField.OnChanged += x => { limitData.lower = x; MarkAsModified(); };
+            limitLowerField.OnFocusLost += ConfirmModify;
+
+            limitUpperField.OnChanged += x => { limitData.upper = x; MarkAsModified(); };
+            limitUpperField.OnFocusLost += ConfirmModify;
+
+            layout.AddElement(limitLowerField);
+            layout.AddElement(limitUpperField);
+            limitCommonGUI = new LimitCommonGUI("linearRange", limit.CommonData, layout, properties);
+            limitCommonGUI.OnChanged += x => MarkAsModified();
+            limitCommonGUI.OnConfirmed += ConfirmModify;
+        }
+
+        /// <summary>
+        /// Marks the contents of the inspector as modified.
+        /// </summary>
+        private void MarkAsModified()
+        {
+            if (OnChanged != null)
+                OnChanged(limitData, limitCommonGUI.LimitData);
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications.
+        /// </summary>
+        private void ConfirmModify()
+        {
+            if (OnConfirmed != null)
+                OnConfirmed();
+        }
+    }
+
+    /// <summary>
+    /// Draws GUI elements for inspecting an <see cref="LimitAngularRange"/> object.
+    /// </summary>
+    internal class LimitAngularRangeGUI
+    {
+        private LimitAngularRangeData limitData;
+
+        private GUISliderField limitLowerField = new GUISliderField(0, 360, new LocEdString("Lower"));
+        private GUISliderField limitUpperField = new GUISliderField(0, 360, new LocEdString("Upper"));
+        private LimitCommonGUI limitCommonGUI;
+
+        public Action<LimitAngularRangeData, LimitCommonData> OnChanged;
+        public Action OnConfirmed;
+
+        /// <summary>
+        /// Current limit properties.
+        /// </summary>
+        public LimitAngularRange Limit
+        {
+            set
+            {
+                limitData = value.Data;
+
+                limitLowerField.Value = limitData.lower.Degrees;
+                limitUpperField.Value = limitData.upper.Degrees;
+                limitCommonGUI.LimitData = value.CommonData;
+            }
+        }
+
+        /// <summary>
+        /// Constructs a new set of GUI elements for inspecting the limit object.
+        /// </summary>
+        /// <param name="limit">Initial values to assign to the GUI elements.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        /// <param name="properties">A set of properties that are persisted by the parent inspector. Used for saving state.
+        ///                          </param>
+        public LimitAngularRangeGUI(LimitAngularRange limit, GUILayout layout, SerializableProperties properties)
+        {
+            this.limitData = limit.Data;
+
+            limitLowerField.OnChanged += x => { limitData.lower = new Degree(x); MarkAsModified(); };
+            limitLowerField.OnFocusLost += ConfirmModify;
+
+            limitUpperField.OnChanged += x => { limitData.upper = new Degree(x); MarkAsModified(); };
+            limitUpperField.OnFocusLost += ConfirmModify;
+
+            layout.AddElement(limitLowerField);
+            layout.AddElement(limitUpperField);
+            limitCommonGUI = new LimitCommonGUI("angularRange", limit.CommonData, layout, properties);
+            limitCommonGUI.OnChanged += x => MarkAsModified();
+            limitCommonGUI.OnConfirmed += ConfirmModify;
+        }
+
+        /// <summary>
+        /// Marks the contents of the inspector as modified.
+        /// </summary>
+        private void MarkAsModified()
+        {
+            if (OnChanged != null)
+                OnChanged(limitData, limitCommonGUI.LimitData);
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications.
+        /// </summary>
+        private void ConfirmModify()
+        {
+            if (OnConfirmed != null)
+                OnConfirmed();
+        }
+    }
+
+    /// <summary>
+    /// Draws GUI elements for inspecting an <see cref="LimitConeRange"/> object.
+    /// </summary>
+    internal class LimitConeRangeGUI
+    {
+        private LimitConeRangeData limitData;
+
+        private GUISliderField yLimitAngleField = new GUISliderField(0, 360, new LocEdString("Y limit"));
+        private GUISliderField zLimitAngleField = new GUISliderField(0, 360, new LocEdString("Z limit"));
+        private LimitCommonGUI limitCommonGUI;
+
+        public Action<LimitConeRangeData, LimitCommonData> OnChanged;
+        public Action OnConfirmed;
+
+        /// <summary>
+        /// Current limit properties.
+        /// </summary>
+        public LimitConeRange Limit
+        {
+            set
+            {
+                limitData = value.Data;
+
+                yLimitAngleField.Value = limitData.yLimitAngle.Degrees;
+                zLimitAngleField.Value = limitData.zLimitAngle.Degrees;
+                limitCommonGUI.LimitData = value.CommonData;
+            }
+        }
+
+        /// <summary>
+        /// Constructs a new set of GUI elements for inspecting the limit object.
+        /// </summary>
+        /// <param name="limit">Initial values to assign to the GUI elements.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        /// <param name="properties">A set of properties that are persisted by the parent inspector. Used for saving state.
+        ///                          </param>
+        public LimitConeRangeGUI(LimitConeRange limit, GUILayout layout, SerializableProperties properties)
+        {
+            this.limitData = limit.Data;
+
+            yLimitAngleField.OnChanged += x => { limitData.yLimitAngle = new Degree(x); MarkAsModified(); };
+            yLimitAngleField.OnFocusLost += ConfirmModify;
+
+            zLimitAngleField.OnChanged += x => { limitData.zLimitAngle = new Degree(x); MarkAsModified(); };
+            zLimitAngleField.OnFocusLost += ConfirmModify;
+
+            layout.AddElement(yLimitAngleField);
+            layout.AddElement(zLimitAngleField);
+            limitCommonGUI = new LimitCommonGUI("coneRange", limit.CommonData, layout, properties);
+            limitCommonGUI.OnChanged += x => MarkAsModified();
+            limitCommonGUI.OnConfirmed += ConfirmModify;
+        }
+
+        /// <summary>
+        /// Marks the contents of the inspector as modified.
+        /// </summary>
+        private void MarkAsModified()
+        {
+            if (OnChanged != null)
+                OnChanged(limitData, limitCommonGUI.LimitData);
+        }
+
+        /// <summary>
+        /// Confirms any queued modifications.
+        /// </summary>
+        private void ConfirmModify()
+        {
+            if (OnConfirmed != null)
+                OnConfirmed();
+        }
+    }
+}

+ 2 - 2
MBansheeEditor/Inspectors/PhysicsMaterialInspector.cs

@@ -13,7 +13,7 @@ namespace BansheeEditor
     {
     {
         private GUIFloatField staticFrictionField;
         private GUIFloatField staticFrictionField;
         private GUIFloatField dynamicFrictionField;
         private GUIFloatField dynamicFrictionField;
-        private GUIFloatField restitutionField;
+        private GUISliderField restitutionField;
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
         protected internal override void Initialize()
         protected internal override void Initialize()
@@ -48,7 +48,7 @@ namespace BansheeEditor
 
 
             staticFrictionField = new GUIFloatField(new LocEdString("Static friction"));
             staticFrictionField = new GUIFloatField(new LocEdString("Static friction"));
             dynamicFrictionField = new GUIFloatField(new LocEdString("Dynamic friction"));
             dynamicFrictionField = new GUIFloatField(new LocEdString("Dynamic friction"));
-            restitutionField = new GUIFloatField(new LocEdString("Restitution"));
+            restitutionField = new GUISliderField(0.0f, 1.0f, new LocEdString("Restitution"));
 
 
             staticFrictionField.OnChanged += x =>
             staticFrictionField.OnChanged += x =>
             {
             {

+ 104 - 0
MBansheeEditor/Inspectors/SliderJointInspector.cs

@@ -0,0 +1,104 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Renders an inspector for the <see cref="SliderJoint"/> component.
+    /// </summary>
+    [CustomInspector(typeof(SliderJoint))]
+    public class SliderJointInspector : JointInspector
+    {
+        private GUIToggleField enableLimitField = new GUIToggleField(new LocEdString("Enable limit"));
+        private LimitLinearRangeGUI limitGUI;
+
+        private GUILayoutX limitLayout;
+
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            SliderJoint joint = InspectedObject as SliderJoint;
+
+            if (joint != null)
+                BuildGUI(joint);
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            SliderJoint joint = InspectedObject as SliderJoint;
+            if (joint == null)
+                return InspectableState.NotModified;
+
+            Refresh(joint);
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Creates GUI elements for fields specific to the slider joint.
+        /// </summary>
+        protected void BuildGUI(SliderJoint joint)
+        {
+            enableLimitField.OnChanged += x =>
+            {
+                joint.EnableLimit = x;
+                MarkAsModified();
+                ConfirmModify();
+
+                ToggleLimitFields(x);
+            };
+            
+            Layout.AddElement(enableLimitField);
+            limitLayout = Layout.AddLayoutX();
+            {
+                limitLayout.AddSpace(10);
+
+                GUILayoutY limitContentsLayout = limitLayout.AddLayoutY();
+                limitGUI = new LimitLinearRangeGUI(joint.Limit, limitContentsLayout, Persistent);
+                limitGUI.OnChanged += (x, y) =>
+                {
+                    joint.Limit = new LimitLinearRange(x, y);
+
+                    MarkAsModified();
+                };
+                limitGUI.OnConfirmed += ConfirmModify;
+            }
+            
+            ToggleLimitFields(joint.EnableLimit);
+
+            base.BuildGUI(joint);
+        }
+
+        /// <summary>
+        /// Updates all GUI elements from current values in the joint.
+        /// </summary>
+        /// <param name="joint">Joint to update the GUI from.</param>
+        protected void Refresh(SliderJoint joint)
+        {
+            if (enableLimitField.Value != joint.EnableLimit)
+            {
+                enableLimitField.Value = joint.EnableLimit;
+                ToggleLimitFields(joint.EnableLimit);
+            }
+
+            limitGUI.Limit = joint.Limit;
+            
+            base.Refresh(joint);
+        }
+
+        /// <summary>
+        /// Hides or shows limit property GUI elements.
+        /// </summary>
+        /// <param name="enable">True to show, false to hide.</param>
+        private void ToggleLimitFields(bool enable)
+        {
+            limitLayout.Active = enable;
+        }
+    }
+}

+ 104 - 0
MBansheeEditor/Inspectors/SphericalJointInspector.cs

@@ -0,0 +1,104 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Renders an inspector for the <see cref="SphericalJoint"/> component.
+    /// </summary>
+    [CustomInspector(typeof(SphericalJoint))]
+    public class SphericalJointInspector : JointInspector
+    {
+        private GUIToggleField enableLimitField = new GUIToggleField(new LocEdString("Enable limit"));
+        private LimitConeRangeGUI limitGUI;
+
+        private GUILayoutX limitLayout;
+
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            SphericalJoint joint = InspectedObject as SphericalJoint;
+
+            if (joint != null)
+                BuildGUI(joint);
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            SphericalJoint joint = InspectedObject as SphericalJoint;
+            if (joint == null)
+                return InspectableState.NotModified;
+
+            Refresh(joint);
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Creates GUI elements for fields specific to the spherical joint.
+        /// </summary>
+        protected void BuildGUI(SphericalJoint joint)
+        {
+            enableLimitField.OnChanged += x =>
+            {
+                joint.EnableLimit = x;
+                MarkAsModified();
+                ConfirmModify();
+
+                ToggleLimitFields(x);
+            };
+
+            Layout.AddElement(enableLimitField);
+            limitLayout = Layout.AddLayoutX();
+            {
+                limitLayout.AddSpace(10);
+
+                GUILayoutY limitContentsLayout = limitLayout.AddLayoutY();
+                limitGUI = new LimitConeRangeGUI(joint.Limit, limitContentsLayout, Persistent);
+                limitGUI.OnChanged += (x, y) =>
+                {
+                    joint.Limit = new LimitConeRange(x, y);
+
+                    MarkAsModified();
+                };
+                limitGUI.OnConfirmed += ConfirmModify;
+            }
+
+            ToggleLimitFields(joint.EnableLimit);
+
+            base.BuildGUI(joint);
+        }
+
+        /// <summary>
+        /// Updates all GUI elements from current values in the joint.
+        /// </summary>
+        /// <param name="joint">Joint to update the GUI from.</param>
+        protected void Refresh(SphericalJoint joint)
+        {
+            if (enableLimitField.Value != joint.EnableLimit)
+            {
+                enableLimitField.Value = joint.EnableLimit;
+                ToggleLimitFields(joint.EnableLimit);
+            }
+
+            limitGUI.Limit = joint.Limit;
+
+            base.Refresh(joint);
+        }
+
+        /// <summary>
+        /// Hides or shows limit property GUI elements.
+        /// </summary>
+        /// <param name="enable">True to show, false to hide.</param>
+        private void ToggleLimitFields(bool enable)
+        {
+            limitLayout.Active = enable;
+        }
+    }
+}

+ 8 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -50,12 +50,20 @@
     <Compile Include="Inspectors\BoxColliderInspector.cs" />
     <Compile Include="Inspectors\BoxColliderInspector.cs" />
     <Compile Include="Inspectors\CapsuleColliderInspector.cs" />
     <Compile Include="Inspectors\CapsuleColliderInspector.cs" />
     <Compile Include="Inspectors\ColliderInspector.cs" />
     <Compile Include="Inspectors\ColliderInspector.cs" />
+    <Compile Include="Inspectors\D6JointInspector.cs" />
+    <Compile Include="Inspectors\DistanceJointInspector.cs" />
+    <Compile Include="Inspectors\FixedJointInspector.cs" />
     <Compile Include="Inspectors\GUIWidgetInspector.cs" />
     <Compile Include="Inspectors\GUIWidgetInspector.cs" />
+    <Compile Include="Inspectors\HingeJointInspector.cs" />
+    <Compile Include="Inspectors\JointInspector.cs" />
+    <Compile Include="Inspectors\LimitInspectors.cs" />
     <Compile Include="Inspectors\MeshColliderInspector.cs" />
     <Compile Include="Inspectors\MeshColliderInspector.cs" />
     <Compile Include="Inspectors\PhysicsMaterialInspector.cs" />
     <Compile Include="Inspectors\PhysicsMaterialInspector.cs" />
     <Compile Include="Inspectors\PhysicsMeshInspector.cs" />
     <Compile Include="Inspectors\PhysicsMeshInspector.cs" />
     <Compile Include="Inspectors\PlaneColliderInspector.cs" />
     <Compile Include="Inspectors\PlaneColliderInspector.cs" />
+    <Compile Include="Inspectors\SliderJointInspector.cs" />
     <Compile Include="Inspectors\SphereColliderInspector.cs" />
     <Compile Include="Inspectors\SphereColliderInspector.cs" />
+    <Compile Include="Inspectors\SphericalJointInspector.cs" />
     <Compile Include="LogWindow.cs" />
     <Compile Include="LogWindow.cs" />
     <Compile Include="DefaultSize.cs" />
     <Compile Include="DefaultSize.cs" />
     <Compile Include="DialogBox.cs" />
     <Compile Include="DialogBox.cs" />

+ 1 - 1
MBansheeEngine/Math/Degree.cs

@@ -41,7 +41,7 @@ namespace BansheeEngine
         /// </summary>
         /// </summary>
         /// <param name="value">Value in degrees.</param>
         /// <param name="value">Value in degrees.</param>
         /// <returns>Degree object wrapping the value.</returns>
         /// <returns>Degree object wrapping the value.</returns>
-        public static implicit operator Degree(float value)
+        public static explicit operator Degree(float value)
         {
         {
             return new Degree(value);
             return new Degree(value);
         }
         }

+ 1 - 1
MBansheeEngine/Math/Radian.cs

@@ -41,7 +41,7 @@ namespace BansheeEngine
         /// </summary>
         /// </summary>
         /// <param name="value">Value in degrees.</param>
         /// <param name="value">Value in degrees.</param>
         /// <returns>Radian object wrapping the value.</returns>
         /// <returns>Radian object wrapping the value.</returns>
-        public static implicit operator Radian(float value)
+        public static explicit operator Radian(float value)
         {
         {
             return new Radian(value);
             return new Radian(value);
         }
         }

+ 1 - 1
MBansheeEngine/Physics/HingeJoint.cs

@@ -36,7 +36,7 @@ namespace BansheeEngine
                 if (Native != null)
                 if (Native != null)
                     return Native.Angle;
                     return Native.Angle;
 
 
-                return 0.0f;
+                return new Radian(0.0f);
             }
             }
         }
         }
 
 

+ 432 - 182
MBansheeEngine/Physics/Joint.cs

@@ -337,7 +337,7 @@ namespace BansheeEngine
     }
     }
 
 
     /// <summary>
     /// <summary>
-    /// Controls spring parameters for a physics joint limits. If a limit is soft (body bounces back due to restition when 
+    /// Controls spring parameters for a physics joint limits. If a limit is soft (body bounces back due to restitution when 
     /// the limit is reached) the spring will pull the body back towards the limit using the specified parameters.
     /// the limit is reached) the spring will pull the body back towards the limit using the specified parameters.
     /// </summary>
     /// </summary>
     [StructLayout(LayoutKind.Sequential), SerializeObject]
     [StructLayout(LayoutKind.Sequential), SerializeObject]
@@ -490,26 +490,62 @@ namespace BansheeEngine
     [SerializeObject]
     [SerializeObject]
     public class D6JointDrive
     public class D6JointDrive
     {
     {
+        [SerializeField]
+        private D6JointDriveData data;
+
         /// <summary>
         /// <summary>
         /// Spring strength. Force proportional to the position error.
         /// Spring strength. Force proportional to the position error.
         /// </summary>
         /// </summary>
-        public float stiffness = 0.0f;
+        public float Stiffness { get { return data.stiffness; } }
 
 
         /// <summary>
         /// <summary>
         /// Damping strength. Force propertional to the velocity error.
         /// Damping strength. Force propertional to the velocity error.
         /// </summary>
         /// </summary>
-        public float damping = 0.0f;
+        public float Damping { get { return data.damping; } }
 
 
         /// <summary>
         /// <summary>
         /// Maximum force the drive can apply.
         /// Maximum force the drive can apply.
         /// </summary>
         /// </summary>
-        public float forceLimit = float.MaxValue;
+        public float ForceLimit { get { return data.forceLimit; } }
 
 
         /// <summary>
         /// <summary>
         /// If true the drive will generate acceleration instead of forces. Acceleration drives are easier to tune as
         /// If true the drive will generate acceleration instead of forces. Acceleration drives are easier to tune as
         /// they account for the masses of the actors to which the joint is attached.
         /// they account for the masses of the actors to which the joint is attached.
         /// </summary>
         /// </summary>
-        public bool acceleration = false;
+        public bool Acceleration { get { return data.acceleration; } }
+
+        /// <summary>
+        /// Gets drive properties.
+        /// </summary>
+        public D6JointDriveData Data
+        {
+            get { return data; }
+        }
+
+        /// <summary>
+        /// Constructs a new D6 joint drive.
+        /// </summary>
+        /// <param name="stiffness"><see cref="Stiffness"/></param>
+        /// <param name="damping"><see cref="Damping"/></param>
+        /// <param name="forceLimit"><see cref="ForceLimit"/></param>
+        /// <param name="acceleration"><see cref="Acceleration"/></param>
+        public D6JointDrive(float stiffness = 0.0f, float damping = 0.0f, float forceLimit = float.MaxValue,
+            bool acceleration = false)
+        {
+            data.stiffness = stiffness;
+            data.damping = damping;
+            data.forceLimit = forceLimit;
+            data.acceleration = acceleration;
+        }
+
+        /// <summary>
+        /// Constructs a new D6 joint drive.
+        /// </summary>
+        /// <param name="data">Properties to initialize the drive with.</param>
+        public D6JointDrive(D6JointDriveData data)
+        {
+            this.data = data;
+        }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
         public override bool Equals(object rhs)
         public override bool Equals(object rhs)
@@ -517,8 +553,8 @@ namespace BansheeEngine
             if (rhs is D6JointDrive)
             if (rhs is D6JointDrive)
             {
             {
                 D6JointDrive other = (D6JointDrive)rhs;
                 D6JointDrive other = (D6JointDrive)rhs;
-                return stiffness == other.stiffness && damping == other.damping && forceLimit == other.forceLimit 
-                    && acceleration == other.acceleration;
+                return Stiffness == other.Stiffness && Damping == other.Damping && ForceLimit == other.ForceLimit 
+                    && Acceleration == other.Acceleration;
             }
             }
 
 
             return false;
             return false;
@@ -538,12 +574,9 @@ namespace BansheeEngine
         /// Used for accessing drive data from native code.
         /// Used for accessing drive data from native code.
         /// </summary>
         /// </summary>
         /// <param name="output">Native readable drive structure.</param>
         /// <param name="output">Native readable drive structure.</param>
-        private void Internal_GetNative(ref ScriptD6JointDrive output)
+        private void Internal_GetNative(out D6JointDriveData output)
         {
         {
-            output.stiffness = stiffness;
-            output.damping = damping;
-            output.forceLimit = forceLimit;
-            output.acceleration = acceleration;
+            output = data;
         }
         }
     }
     }
 
 
@@ -553,26 +586,62 @@ namespace BansheeEngine
     [SerializeObject]
     [SerializeObject]
     public class HingeJointDrive
     public class HingeJointDrive
     {
     {
+        [SerializeField]
+        private HingeJointDriveData data;
+
         /// <summary>
         /// <summary>
         /// Target speed of the joint.
         /// Target speed of the joint.
         /// </summary>
         /// </summary>
-        public float speed = 0.0f;
+        public float Speed { get { return data.speed; } }
 
 
         /// <summary>
         /// <summary>
         /// Maximum torque the drive is allowed to apply.
         /// Maximum torque the drive is allowed to apply.
         /// </summary>
         /// </summary>
-        public float forceLimit = float.MaxValue;
+        public float ForceLimit { get { return data.forceLimit; } }
 
 
         /// <summary>
         /// <summary>
         /// Scales the velocity of the first body, and its response to drive torque is scaled down.
         /// Scales the velocity of the first body, and its response to drive torque is scaled down.
         /// </summary>
         /// </summary>
-        public float gearRatio = 1.0f;
+        public float GearRatio { get { return data.gearRatio; } }
 
 
         /// <summary>
         /// <summary>
         /// If the joint is moving faster than the drive's target speed, the drive will try to break. If you don't want
         /// If the joint is moving faster than the drive's target speed, the drive will try to break. If you don't want
         /// the breaking to happen set this to true.
         /// the breaking to happen set this to true.
         /// </summary>
         /// </summary>
-        public bool freeSpin = false;
+        public bool FreeSpin { get { return data.freeSpin; } }
+
+        /// <summary>
+        /// Gets drive properties.
+        /// </summary>
+        public HingeJointDriveData Data
+        {
+            get { return data; }
+        }
+
+        /// <summary>
+        /// Constructs a new hinge joint drive.
+        /// </summary>
+        /// <param name="speed"><see cref="Speed"/></param>
+        /// <param name="forceLimit"><see cref="ForceLimit"/></param>
+        /// <param name="gearRatio"><see cref="GearRatio"/></param>
+        /// <param name="freeSpin"><see cref="FreeSpin"/></param>
+        public HingeJointDrive(float speed = 0.0f, float forceLimit = float.MaxValue, 
+            float gearRatio = 1.0f, bool freeSpin = false)
+        {
+            data.speed = speed;
+            data.forceLimit = forceLimit;
+            data.gearRatio = gearRatio;
+            data.freeSpin = freeSpin;
+        }
+
+        /// <summary>
+        /// Constructs a new hinge joint drive.
+        /// </summary>
+        /// <param name="data">Properties to initialize the drive with.</param>
+        public HingeJointDrive(HingeJointDriveData data)
+        {
+            this.data = data;
+        }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
         public override bool Equals(object rhs)
         public override bool Equals(object rhs)
@@ -580,8 +649,8 @@ namespace BansheeEngine
             if (rhs is HingeJointDrive)
             if (rhs is HingeJointDrive)
             {
             {
                 HingeJointDrive other = (HingeJointDrive)rhs;
                 HingeJointDrive other = (HingeJointDrive)rhs;
-                return speed == other.speed && gearRatio == other.gearRatio && forceLimit == other.forceLimit
-                    && freeSpin == other.freeSpin;
+                return data.speed == other.data.speed && data.gearRatio == other.data.gearRatio && 
+                    data.forceLimit == other.data.forceLimit && data.freeSpin == other.data.freeSpin;
             }
             }
 
 
             return false;
             return false;
@@ -601,12 +670,9 @@ namespace BansheeEngine
         /// Used for accessing drive data from native code.
         /// Used for accessing drive data from native code.
         /// </summary>
         /// </summary>
         /// <param name="output">Native readable drive structure.</param>
         /// <param name="output">Native readable drive structure.</param>
-        private void Internal_GetNative(ref ScriptHingeJointDrive output)
+        private void Internal_GetNative(out HingeJointDriveData output)
         {
         {
-            output.speed = speed;
-            output.forceLimit = forceLimit;
-            output.gearRatio = gearRatio;
-            output.freeSpin = freeSpin;
+            output = data;
         }
         }
     };
     };
 
 
@@ -615,19 +681,51 @@ namespace BansheeEngine
     /// </summary>
     /// </summary>
     [SerializeObject]
     [SerializeObject]
     public class LimitCommon
     public class LimitCommon
-	{
-		public LimitCommon(float contactDist = -1.0f)
+    {
+        private LimitCommonData data;
+
+        /// <summary>
+        /// Distance from the limit at which it becomes active. Allows the solver to activate earlier than the limit is
+        /// reached to avoid breaking the limit.
+        /// </summary>
+        public float ContactDist { get { return data.contactDist; } }
+
+        /// <summary>
+        /// Controls how do objects react when the limit is reached, values closer to zero specify non-ellastic collision,
+        /// while those closer to one specify more ellastic(i.e bouncy) collision.Must be in [0, 1] range.
+        /// </summary>
+		public float Restitution { get { return data.restitution; } }
+
+        /// <summary>
+        /// Spring that controls how are the bodies pulled back towards the limit when they breach it.
+        /// </summary>
+        public Spring Spring { get { return data.spring; } }
+
+        /// <summary>
+        /// Gets properties common to all limit types.
+        /// </summary>
+        public LimitCommonData CommonData
+        {
+            get { return data; }
+        }
+
+        protected LimitCommon(float contactDist = -1.0f)
         {
         {
-            this.contactDist = contactDist;
-            this.restitution = 0.0f;
-            this.spring = new Spring();
+            data.contactDist = contactDist;
+            data.restitution = 0.0f;
+            data.spring = new Spring();
         }
         }
 
 
-        public LimitCommon(Spring spring, float restitution = 0.0f)
+        protected LimitCommon(Spring spring, float restitution = 0.0f)
         {
         {
-            this.contactDist = -1.0f;
-            this.restitution = restitution;
-            this.spring = spring;
+            data.contactDist = -1.0f;
+            data.restitution = restitution;
+            data.spring = spring;
+        }
+
+        protected LimitCommon(LimitCommonData data)
+        {
+            this.data = data;
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
@@ -636,7 +734,7 @@ namespace BansheeEngine
             if (rhs is LimitCommon)
             if (rhs is LimitCommon)
             {
             {
                 LimitCommon other = (LimitCommon)rhs;
                 LimitCommon other = (LimitCommon)rhs;
-                return contactDist == other.contactDist && restitution == other.restitution && spring == other.spring;
+                return ContactDist == other.ContactDist && Restitution == other.Restitution && Spring == other.Spring;
             }
             }
 
 
             return false;
             return false;
@@ -651,31 +749,34 @@ namespace BansheeEngine
         {
         {
             return !(a == b);
             return !(a == b);
         }
         }
+    }
+
+    /// <summary>
+    /// Represents a joint limit between two distance values. Lower value must be less than the upper value.
+    /// </summary>
+    [SerializeObject]
+    public class LimitLinearRange : LimitCommon
+    {
+        private LimitLinearRangeData data;
 
 
         /// <summary>
         /// <summary>
-        /// Distance from the limit at which it becomes active. Allows the solver to activate earlier than the limit is
-        /// reached to avoid breaking the limit.
+        /// Lower distance of the limit. Must be less than <see cref="Upper"/>.
         /// </summary>
         /// </summary>
-        public float contactDist;
+        public float Lower { get { return data.lower; } }
 
 
         /// <summary>
         /// <summary>
-        /// Controls how do objects react when the limit is reached, values closer to zero specify non-ellastic collision,
-        /// while those closer to one specify more ellastic(i.e bouncy) collision.Must be in [0, 1] range.
+        /// Upper distance of the limit. Must be greater than <see cref="Lower"/>.
         /// </summary>
         /// </summary>
-		public float restitution;
+        public float Upper { get { return data.upper; } }
 
 
         /// <summary>
         /// <summary>
-        /// Spring that controls how are the bodies pulled back towards the limit when they breach it.
+        /// Gets properties of the linear limit range.
         /// </summary>
         /// </summary>
-        public Spring spring;
-    }
+        public LimitLinearRangeData Data
+        {
+            get { return data; }
+        }
 
 
-    /// <summary>
-    /// Represents a joint limit between two distance values. Lower value must be less than the upper value.
-    /// </summary>
-    [SerializeObject]
-    public class LimitLinearRange : LimitCommon
-	{
         /// <summary>
         /// <summary>
         /// Constructs an empty limit.
         /// Constructs an empty limit.
         /// </summary>
         /// </summary>
@@ -685,35 +786,40 @@ namespace BansheeEngine
         /// <summary>
         /// <summary>
         /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
         /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
         /// </summary>
         /// </summary>
-        /// <param name="lower">Lower distance of the limit.Must be less than <paramref name="upper"/>.</param>
-        /// <param name="upper">Upper distance of the limit.Must be more than <paramref name="lower"/>.</param>
-        /// <param name="contactDist">Distance from the limit at which it becomes active.Allows the solver to activate 
-        ///                           earlier than the limit is reached to avoid breaking the limit.Specify -1 for the 
-        ///                           default.</param>
+        /// <param name="lower"><see cref="Lower"/></param>
+        /// <param name="upper"><see cref="Upper"/></param>
+        /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
         public LimitLinearRange(float lower, float upper, float contactDist = -1.0f)
         public LimitLinearRange(float lower, float upper, float contactDist = -1.0f)
             :base(contactDist)
             :base(contactDist)
         {
         {
-            this.lower = lower;
-            this.upper = upper;
-
+            data.lower = lower;
+            data.upper = upper;
         }
         }
 
 
         /// <summary>
         /// <summary>
         /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
         /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
         /// parameter and will be pulled back towards the limit by the provided spring.
         /// parameter and will be pulled back towards the limit by the provided spring.
         /// </summary>
         /// </summary>
-        /// <param name="lower">Lower distance of the limit. Must be less than <paramref name="upper"/>.</param>
-        /// <param name="upper">Upper distance of the limit. Must be more than <paramref name="lower"/>.</param>
-        /// <param name="spring">Spring that controls how are the bodies pulled back towards the limit when they breach it.
-        ///                      </param>
-        /// <param name="restitution">Controls how do objects react when the limit is reached, values closer to zero specify
-        ///                           non-ellastic collision, while those closer to one specify more ellastic(i.e bouncy)
-        ///                           collision.Must be in [0, 1] range.</param>
+        /// <param name="lower"><see cref="Lower"/></param>
+        /// <param name="upper"><see cref="Upper"/></param>
+        /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
+        /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
         public LimitLinearRange(float lower, float upper, Spring spring, float restitution = 0.0f)
         public LimitLinearRange(float lower, float upper, Spring spring, float restitution = 0.0f)
             :base(spring, restitution)
             :base(spring, restitution)
         {
         {
-            this.lower = lower;
-            this.upper = upper;
+            data.lower = lower;
+            data.upper = upper;
+        }
+
+        /// <summary>
+        /// Constructs a new limit from the provided properties.
+        /// </summary>
+        /// <param name="limitData">Linear range specific properties.</param>
+        /// <param name="commonData">Properties common to all limit types.</param>
+        public LimitLinearRange(LimitLinearRangeData limitData, LimitCommonData commonData)
+            :base(commonData)
+        {
+            this.data = limitData;
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
@@ -722,7 +828,7 @@ namespace BansheeEngine
             if (rhs is LimitLinearRange)
             if (rhs is LimitLinearRange)
             {
             {
                 LimitLinearRange other = (LimitLinearRange)rhs;
                 LimitLinearRange other = (LimitLinearRange)rhs;
-                return base.Equals(rhs) && lower == other.lower && upper == other.upper;
+                return base.Equals(rhs) && Lower == other.Lower && Upper == other.Upper;
             }
             }
 
 
             return false;
             return false;
@@ -738,27 +844,17 @@ namespace BansheeEngine
             return !(a == b);
             return !(a == b);
         }
         }
 
 
-        /// <summary>
-        /// Lower distance of the limit. Must be less than #upper.
-        /// </summary>
-        public float lower;
-
-        /// <summary>
-        /// Upper distance of the limit. Must be more than #lower.
-        /// </summary>
-        public float upper;
-
         /// <summary>
         /// <summary>
         /// Used for accessing limit data from native code.
         /// Used for accessing limit data from native code.
         /// </summary>
         /// </summary>
         /// <param name="output">Native readable limit structure.</param>
         /// <param name="output">Native readable limit structure.</param>
         private void Internal_GetNative(ref ScriptLimitLinearRange output)
         private void Internal_GetNative(ref ScriptLimitLinearRange output)
         {
         {
-            output.contactDist = contactDist;
-            output.resitution = restitution;
-            output.spring = spring;
-            output.lower = lower;
-            output.upper = upper;
+            output.contactDist = ContactDist;
+            output.restitution = Restitution;
+            output.spring = Spring;
+            output.lower = Lower;
+            output.upper = Upper;
         }
         }
     }
     }
 
 
@@ -767,7 +863,22 @@ namespace BansheeEngine
     /// </summary>
     /// </summary>
     [SerializeObject]
     [SerializeObject]
     public class LimitLinear : LimitCommon
     public class LimitLinear : LimitCommon
-	{
+    {
+        private LimitLinearData data;
+
+        /// <summary>
+        /// Distance at which the limit becomes active.
+        /// </summary>
+        public float Extent { get { return data.extent; } }
+
+        /// <summary>
+        /// Gets properties of the linear limit.
+        /// </summary>
+        public LimitLinearData Data
+        {
+            get { return data; }
+        }
+
         /// <summary>
         /// <summary>
         /// Constructs an empty limit.
         /// Constructs an empty limit.
         /// </summary>
         /// </summary>
@@ -777,30 +888,36 @@ namespace BansheeEngine
         /// <summary>
         /// <summary>
         /// Constructs a hard limit.Once the limit is reached the movement of the attached bodies will come to a stop.
         /// Constructs a hard limit.Once the limit is reached the movement of the attached bodies will come to a stop.
         /// </summary>
         /// </summary>
-        /// <param name="extent">Distance at which the limit becomes active.</param>
-        /// <param name="contactDist">Distance from the limit at which it becomes active. Allows the solver to activate 
-        ///                           earlier than the limit is reached to avoid breaking the limit.Specify -1 for the 
-        ///                           default.</param>
+        /// <param name="extent"><see cref="Extent"/></param>
+        /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
         public LimitLinear(float extent, float contactDist = -1.0f)
         public LimitLinear(float extent, float contactDist = -1.0f)
 			:base(contactDist)
 			:base(contactDist)
         {
         {
-            this.extent = extent;
+            data.extent = extent;
         }
         }
 
 
         /// <summary>
         /// <summary>
         /// Constructs a soft limit.Once the limit is reached the bodies will bounce back according to the resitution
         /// Constructs a soft limit.Once the limit is reached the bodies will bounce back according to the resitution
         /// parameter and will be pulled back towards the limit by the provided spring.
         /// parameter and will be pulled back towards the limit by the provided spring.
         /// </summary>
         /// </summary>
-        /// <param name="extent">Distance at which the limit becomes active. </param>
-        /// <param name="spring">Spring that controls how are the bodies pulled back towards the limit when they breach it.
-        ///                      </param>
-        /// <param name="restitution">Controls how do objects react when the limit is reached, values closer to zero specify
-        ///                           non-ellastic collision, while those closer to one specify more ellastic(i.e bouncy)
-        ///                           collision.Must be in [0, 1] range.</param>
+        /// <param name="extent"><see cref="Extent"/></param>
+        /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
+        /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
 		public LimitLinear(float extent, Spring spring, float restitution = 0.0f)
 		public LimitLinear(float extent, Spring spring, float restitution = 0.0f)
 			:base(spring, restitution)
 			:base(spring, restitution)
         {
         {
-            this.extent = extent;
+            data.extent = extent;
+        }
+
+        /// <summary>
+        /// Constructs a new limit from the provided properties.
+        /// </summary>
+        /// <param name="limitData">Linear limit specific properties.</param>
+        /// <param name="commonData">Properties common to all limit types.</param>
+        public LimitLinear(LimitLinearData limitData, LimitCommonData commonData)
+            :base(commonData)
+        {
+            this.data = limitData;
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
@@ -809,7 +926,7 @@ namespace BansheeEngine
             if (rhs is LimitLinear)
             if (rhs is LimitLinear)
             {
             {
                 LimitLinear other = (LimitLinear)rhs;
                 LimitLinear other = (LimitLinear)rhs;
-                return base.Equals(rhs) && extent == other.extent;
+                return base.Equals(rhs) && Extent == other.Extent;
             }
             }
 
 
             return false;
             return false;
@@ -825,21 +942,16 @@ namespace BansheeEngine
             return !(a == b);
             return !(a == b);
         }
         }
 
 
-        /// <summary>
-        /// Distance at which the limit becomes active.
-        /// </summary>
-        public float extent = 0.0f;
-
         /// <summary>
         /// <summary>
         /// Used for accessing limit data from native code.
         /// Used for accessing limit data from native code.
         /// </summary>
         /// </summary>
         /// <param name="output">Native readable limit structure.</param>
         /// <param name="output">Native readable limit structure.</param>
         private void Internal_GetNative(ref ScriptLimitLinear output)
         private void Internal_GetNative(ref ScriptLimitLinear output)
         {
         {
-            output.contactDist = contactDist;
-            output.resitution = restitution;
-            output.spring = spring;
-            output.extent = extent;
+            output.contactDist = ContactDist;
+            output.restitution = Restitution;
+            output.spring = Spring;
+            output.extent = Extent;
         }
         }
     }
     }
 
 
@@ -849,6 +961,26 @@ namespace BansheeEngine
     [SerializeObject]
     [SerializeObject]
     public class LimitAngularRange : LimitCommon
     public class LimitAngularRange : LimitCommon
 	{
 	{
+        private LimitAngularRangeData data;
+
+        /// <summary>
+        /// Lower angle of the limit. Must be less than <see cref="Upper"/>.
+        /// </summary>
+        public Radian Lower { get { return data.lower; } }
+
+        /// <summary>
+        /// Upper angle of the limit. Must be greater than <see cref="Lower"/>.
+        /// </summary>
+        public Radian Upper { get { return data.upper; } }
+
+        /// <summary>
+        /// Gets properties of the angular limit range.
+        /// </summary>
+        public LimitAngularRangeData Data
+        {
+            get { return data; }
+        }
+
         /// <summary>
         /// <summary>
         /// Constructs an empty limit.
         /// Constructs an empty limit.
         /// </summary>
         /// </summary>
@@ -858,34 +990,40 @@ namespace BansheeEngine
         /// <summary>
         /// <summary>
         /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
         /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
         /// </summary>
         /// </summary>
-        /// <param name="lower">Lower angle of the limit. Must be less than <paramref name="upper"/>.</param>
-        /// <param name="upper">Upper angle of the limit. Must be more than <paramref name="lower"/>.</param>
-        /// <param name="contactDist">Distance from the limit at which it becomes active. Allows the solver to activate 
-        ///                           earlier than the limit is reached to avoid breaking the limit.Specify -1 for the 
-        ///                           default.</param>
+        /// <param name="lower"><see cref="Lower"/></param>
+        /// <param name="upper"><see cref="Upper"/></param>
+        /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
         public LimitAngularRange(Radian lower, Radian upper, float contactDist = -1.0f)
         public LimitAngularRange(Radian lower, Radian upper, float contactDist = -1.0f)
             : base(contactDist)
             : base(contactDist)
         {
         {
-            this.lower = lower;
-            this.upper = upper;
+            data.lower = lower;
+            data.upper = upper;
         }
         }
 
 
         /// <summary>
         /// <summary>
         /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
         /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
         /// parameter and will be pulled back towards the limit by the provided spring.
         /// parameter and will be pulled back towards the limit by the provided spring.
         /// </summary>
         /// </summary>
-        /// <param name="lower">Lower angle of the limit. Must be less than <paramref name="upper"/>.</param>
-        /// <param name="upper">Upper angle of the limit. Must be more than <paramref name="lower"/>.</param>
-        /// <param name="spring">Spring that controls how are the bodies pulled back towards the limit when they breach it.
-        ///                      </param>
-        /// <param name="restitution">Controls how do objects react when the limit is reached, values closer to zero specify
-        ///                           non-ellastic collision, while those closer to one specify more ellastic(i.e bouncy)
-        ///                           collision.Must be in [0, 1] range.</param>
+        /// <param name="lower"><see cref="Lower"/></param>
+        /// <param name="upper"><see cref="Upper"/></param>
+        /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
+        /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
         public LimitAngularRange(Radian lower, Radian upper, Spring spring, float restitution = 0.0f)
         public LimitAngularRange(Radian lower, Radian upper, Spring spring, float restitution = 0.0f)
             : base(spring, restitution)
             : base(spring, restitution)
         {
         {
-            this.lower = lower;
-            this.upper = upper;
+            data.lower = lower;
+            data.upper = upper;
+        }
+
+        /// <summary>
+        /// Constructs a new limit from the provided properties.
+        /// </summary>
+        /// <param name="limitData">Angular limit range specific properties.</param>
+        /// <param name="commonData">Properties common to all limit types.</param>
+        public LimitAngularRange(LimitAngularRangeData limitData, LimitCommonData commonData)
+            :base(commonData)
+        {
+            this.data = limitData;
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
@@ -894,7 +1032,7 @@ namespace BansheeEngine
             if (rhs is LimitAngularRange)
             if (rhs is LimitAngularRange)
             {
             {
                 LimitAngularRange other = (LimitAngularRange)rhs;
                 LimitAngularRange other = (LimitAngularRange)rhs;
-                return base.Equals(rhs) && lower == other.lower && upper == other.upper;
+                return base.Equals(rhs) && Lower == other.Lower && Upper == other.Upper;
             }
             }
 
 
             return false;
             return false;
@@ -910,27 +1048,17 @@ namespace BansheeEngine
             return !(a == b);
             return !(a == b);
         }
         }
 
 
-        /// <summary>
-        /// Lower angle of the limit. Must be less than #upper.
-        /// </summary>
-        public Radian lower = new Radian(0.0f);
-
-        /// <summary>
-        /// Upper angle of the limit. Must be less than #lower.
-        /// </summary>
-        public Radian upper = new Radian(0.0f);
-
         /// <summary>
         /// <summary>
         /// Used for accessing limit data from native code.
         /// Used for accessing limit data from native code.
         /// </summary>
         /// </summary>
         /// <param name="output">Native readable limit structure.</param>
         /// <param name="output">Native readable limit structure.</param>
         private void Internal_GetNative(ref ScriptLimitAngularRange output)
         private void Internal_GetNative(ref ScriptLimitAngularRange output)
         {
         {
-            output.contactDist = contactDist;
-            output.resitution = restitution;
-            output.spring = spring;
-            output.lower = lower;
-            output.upper = upper;
+            output.contactDist = ContactDist;
+            output.restitution = Restitution;
+            output.spring = Spring;
+            output.lower = Lower;
+            output.upper = Upper;
         }
         }
     }
     }
 
 
@@ -939,48 +1067,73 @@ namespace BansheeEngine
     /// </summary>
     /// </summary>
     [SerializeObject]
     [SerializeObject]
     public class LimitConeRange : LimitCommon
     public class LimitConeRange : LimitCommon
-	{
+    {
+        private LimitConeRangeData data;
+
+        /// <summary>
+        /// Y angle of the cone. Movement is constrainted between 0 and this angle on the Y axis.
+        /// </summary>
+        public Radian YLimitAngle { get { return data.yLimitAngle; } }
+
+        /// <summary>
+        /// Z angle of the cone. Movement is constrainted between 0 and this angle on the Z axis.
+        /// </summary>
+        public Radian ZLimitAngle { get { return data.zLimitAngle; } }
+
+        /// <summary>
+        /// Gets properties of the cone limit range.
+        /// </summary>
+        public LimitConeRangeData Data
+        {
+            get { return data; }
+        }
+
         /// <summary>
         /// <summary>
         /// Constructs a limit with a 45 degree cone.
         /// Constructs a limit with a 45 degree cone.
         /// </summary>
         /// </summary>
         public LimitConeRange()
         public LimitConeRange()
-		{ }
+        {
+            data.yLimitAngle = new Radian(MathEx.Pi * 0.5f);
+            data.zLimitAngle = new Radian(MathEx.Pi * 0.5f);
+        }
 
 
         /// <summary>
         /// <summary>
         /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
         /// Constructs a hard limit. Once the limit is reached the movement of the attached bodies will come to a stop.
         /// </summary>
         /// </summary>
-        /// <param name="yLimitAngle">Y angle of the cone. Movement is constrainted between 0 and this angle on the Y axis.
-        ///                           </param>
-        /// <param name="zLimitAngle">Z angle of the cone. Movement is constrainted between 0 and this angle on the Z axis.
-        ///                           </param>
-        /// <param name="contactDist">Distance from the limit at which it becomes active. Allows the solver to activate 
-        ///                           earlier than the limit is reached to avoid breaking the limit.Specify -1 for the
-        ///                           default.</param>
+        /// <param name="yLimitAngle"><see cref="YLimitAngle"/></param>
+        /// <param name="zLimitAngle"><see cref="ZLimitAngle"/></param>
+        /// <param name="contactDist"><see cref="LimitCommon.ContactDist"/></param>
         public LimitConeRange(Radian yLimitAngle, Radian zLimitAngle, float contactDist = -1.0f)
         public LimitConeRange(Radian yLimitAngle, Radian zLimitAngle, float contactDist = -1.0f)
             : base(contactDist)
             : base(contactDist)
         {
         {
-            this.yLimitAngle = yLimitAngle;
-            this.zLimitAngle = zLimitAngle;
+            data.yLimitAngle = yLimitAngle;
+            data.zLimitAngle = zLimitAngle;
         }
         }
 
 
         /// <summary>
         /// <summary>
         /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
         /// Constructs a soft limit. Once the limit is reached the bodies will bounce back according to the resitution
         /// parameter and will be pulled back towards the limit by the provided spring.
         /// parameter and will be pulled back towards the limit by the provided spring.
         /// </summary>
         /// </summary>
-        /// <param name="yLimitAngle">Y angle of the cone. Movement is constrainted between 0 and this angle on the Y axis.
-        ///                           </param>
-        /// <param name="zLimitAngle">Z angle of the cone. Movement is constrainted between 0 and this angle on the Z axis.
-        ///                           </param>
-        /// <param name="spring">Spring that controls how are the bodies pulled back towards the limit when they breach it.
-        ///                      </param>
-        /// <param name="restitution">Controls how do objects react when the limit is reached, values closer to zero specify
-        ///                           non-ellastic collision, while those closer to one specify more ellastic(i.e bouncy)
-        ///                           collision.Must be in [0, 1] range.</param>
+        /// <param name="yLimitAngle"><see cref="YLimitAngle"/></param>
+        /// <param name="zLimitAngle"><see cref="ZLimitAngle"/></param>
+        /// <param name="spring"><see cref="LimitCommon.Spring"/></param>
+        /// <param name="restitution"><see cref="LimitCommon.Restitution"/></param>
         public LimitConeRange(Radian yLimitAngle, Radian zLimitAngle, Spring spring, float restitution = 0.0f)
         public LimitConeRange(Radian yLimitAngle, Radian zLimitAngle, Spring spring, float restitution = 0.0f)
             : base(spring, restitution)
             : base(spring, restitution)
         {
         {
-            this.yLimitAngle = yLimitAngle;
-            this.zLimitAngle = zLimitAngle;
+            data.yLimitAngle = yLimitAngle;
+            data.zLimitAngle = zLimitAngle;
+        }
+
+        /// <summary>
+        /// Constructs a new limit from the provided properties.
+        /// </summary>
+        /// <param name="limitData">Cone limit range specific properties.</param>
+        /// <param name="commonData">Properties common to all limit types.</param>
+        public LimitConeRange(LimitConeRangeData limitData, LimitCommonData commonData)
+            :base(commonData)
+        {
+            this.data = limitData;
         }
         }
 
 
         /// <inheritdoc/>
         /// <inheritdoc/>
@@ -989,7 +1142,7 @@ namespace BansheeEngine
             if (rhs is LimitConeRange)
             if (rhs is LimitConeRange)
             {
             {
                 LimitConeRange other = (LimitConeRange)rhs;
                 LimitConeRange other = (LimitConeRange)rhs;
-                return base.Equals(rhs) && yLimitAngle == other.yLimitAngle && zLimitAngle == other.zLimitAngle;
+                return base.Equals(rhs) && YLimitAngle == other.YLimitAngle && ZLimitAngle == other.ZLimitAngle;
             }
             }
 
 
             return false;
             return false;
@@ -1005,54 +1158,151 @@ namespace BansheeEngine
             return !(a == b);
             return !(a == b);
         }
         }
 
 
-        /// <summary>
-        /// Y angle of the cone. Movement is constrainted between 0 and this angle on the Y axis.
-        /// </summary>
-        public Radian yLimitAngle = new Radian(MathEx.Pi * 0.5f);
-
-        /// <summary>
-        /// Z angle of the cone. Movement is constrainted between 0 and this angle on the Z axis.
-        /// </summary>
-        public Radian zLimitAngle = new Radian(MathEx.Pi * 0.5f);
-
         /// <summary>
         /// <summary>
         /// Used for accessing limit data from native code.
         /// Used for accessing limit data from native code.
         /// </summary>
         /// </summary>
         /// <param name="output">Native readable limit structure.</param>
         /// <param name="output">Native readable limit structure.</param>
         private void Internal_GetNative(ref ScriptLimitConeRange output)
         private void Internal_GetNative(ref ScriptLimitConeRange output)
         {
         {
-            output.contactDist = contactDist;
-            output.resitution = restitution;
-            output.spring = spring;
-            output.yLimitAngle = yLimitAngle;
-            output.zLimitAngle = zLimitAngle;
+            output.contactDist = ContactDist;
+            output.restitution = Restitution;
+            output.spring = Spring;
+            output.yLimitAngle = YLimitAngle;
+            output.zLimitAngle = ZLimitAngle;
         }
         }
 	}
 	}
 
 
     /// <summary>
     /// <summary>
-    /// Used for passing HingeJointDrive data between native and managed code.
+    /// Contains data used by HingeJointDrive.
     /// </summary>
     /// </summary>
     [StructLayout(LayoutKind.Sequential)]
     [StructLayout(LayoutKind.Sequential)]
-    internal struct ScriptHingeJointDrive // Note: Must match C++ struct HingeJoint::Drive
+    public struct HingeJointDriveData // Note: Must match C++ struct HingeJoint::Drive
     {
     {
+        /// <summary>
+        /// <see cref="HingeJointDrive.Speed"/>
+        /// </summary>
         public float speed;
         public float speed;
+
+        /// <summary>
+        /// <see cref="HingeJointDrive.ForceLimit"/>
+        /// </summary>
         public float forceLimit;
         public float forceLimit;
+
+        /// <summary>
+        /// <see cref="HingeJointDrive.GearRatio"/>
+        /// </summary>
         public float gearRatio;
         public float gearRatio;
+
+        /// <summary>
+        /// <see cref="HingeJointDrive.FreeSpin"/>
+        /// </summary>
         public bool freeSpin;
         public bool freeSpin;
     }
     }
 
 
     /// <summary>
     /// <summary>
-    /// Used for passing D6JointDrive data between native and managed code.
+    /// Contains data used by D6JointDrive.
     /// </summary>
     /// </summary>
     [StructLayout(LayoutKind.Sequential)]
     [StructLayout(LayoutKind.Sequential)]
-    internal struct ScriptD6JointDrive // Note: Must match C++ struct D6Joint::Drive
+    public struct D6JointDriveData // Note: Must match C++ struct D6Joint::Drive
     {
     {
+        /// <summary>
+        /// <see cref="D6JointDrive.Stiffness"/>
+        /// </summary>
         public float stiffness;
         public float stiffness;
+
+        /// <summary>
+        /// <see cref="D6JointDrive.Damping"/>
+        /// </summary>
         public float damping;
         public float damping;
+
+        /// <summary>
+        /// <see cref="D6JointDrive.ForceLimit"/>
+        /// </summary>
         public float forceLimit;
         public float forceLimit;
+
+        /// <summary>
+        /// <see cref="D6JointDrive.Acceleration"/>
+        /// </summary>
         public bool acceleration;
         public bool acceleration;
     }
     }
 
 
+    /// <summary>
+    /// Contains data used by LimitCommon.
+    /// </summary>
+    public struct LimitCommonData
+    {
+        /// <summary>
+        /// <see cref="LimitCommon.ContactDist"/>
+        /// </summary>
+        public float contactDist;
+
+        /// <summary>
+        /// <see cref="LimitCommon.Restitution"/>
+        /// </summary>
+        public float restitution;
+
+        /// <summary>
+        /// <see cref="LimitCommon.Spring"/>
+        /// </summary>
+        public Spring spring;
+    }
+
+    /// <summary>
+    /// Contains data used by LimitLinearRange.
+    /// </summary>
+    public struct LimitLinearRangeData
+    {
+        /// <summary>
+        /// <see cref="LimitLinearRange.Lower"/>
+        /// </summary>
+        public float lower;
+        /// <summary>
+        /// <see cref="LimitLinearRange.Upper"/>
+        /// </summary>
+        public float upper;
+    }
+
+    /// <summary>
+    /// Contains data used by LimitLinear.
+    /// </summary>
+    public struct LimitLinearData
+    {
+        /// <summary>
+        /// <see cref="LimitLinearRange.Extent"/>
+        /// </summary>
+        public float extent;
+    }
+
+    /// <summary>
+    /// Contains data used by LimitAngularRange.
+    /// </summary>
+    public struct LimitAngularRangeData
+    {
+        /// <summary>
+        /// <see cref="LimitAngularRange.Lower"/>
+        /// </summary>
+        public Radian lower;
+        /// <summary>
+        /// <see cref="LimitAngularRange.Upper"/>
+        /// </summary>
+        public Radian upper;
+    }
+
+    /// <summary>
+    /// Contains data used by LimitConeRange.
+    /// </summary>
+    public struct LimitConeRangeData
+    {
+        /// <summary>
+        /// <see cref="LimitConeRange.YLimitAngle"/>
+        /// </summary>
+        public Radian yLimitAngle;
+        /// <summary>
+        /// <see cref="LimitConeRange.ZLimitAngle"/>
+        /// </summary>
+        public Radian zLimitAngle;
+    }
+
     /// <summary>
     /// <summary>
     /// Used for passing LimitLinearRange data between native and managed code.
     /// Used for passing LimitLinearRange data between native and managed code.
     /// </summary>
     /// </summary>
@@ -1060,7 +1310,7 @@ namespace BansheeEngine
     internal struct ScriptLimitLinearRange // Note: Must match C++ struct LimitLinearRange
     internal struct ScriptLimitLinearRange // Note: Must match C++ struct LimitLinearRange
     {
     {
         public float contactDist;
         public float contactDist;
-        public float resitution;
+        public float restitution;
         public Spring spring;
         public Spring spring;
         public float lower;
         public float lower;
         public float upper;
         public float upper;
@@ -1073,7 +1323,7 @@ namespace BansheeEngine
     internal struct ScriptLimitLinear // Note: Must match C++ struct LimitLinear
     internal struct ScriptLimitLinear // Note: Must match C++ struct LimitLinear
     {
     {
         public float contactDist;
         public float contactDist;
-        public float resitution;
+        public float restitution;
         public Spring spring;
         public Spring spring;
         public float extent;
         public float extent;
     }
     }
@@ -1085,7 +1335,7 @@ namespace BansheeEngine
     internal struct ScriptLimitAngularRange // Note: Must match C++ struct LimitAngularRange
     internal struct ScriptLimitAngularRange // Note: Must match C++ struct LimitAngularRange
     {
     {
         public float contactDist;
         public float contactDist;
-        public float resitution;
+        public float restitution;
         public Spring spring;
         public Spring spring;
         public Radian lower;
         public Radian lower;
         public Radian upper;
         public Radian upper;
@@ -1098,7 +1348,7 @@ namespace BansheeEngine
     internal struct ScriptLimitConeRange // Note: Must match C++ struct LimitConeRange
     internal struct ScriptLimitConeRange // Note: Must match C++ struct LimitConeRange
     {
     {
         public float contactDist;
         public float contactDist;
-        public float resitution;
+        public float restitution;
         public Spring spring;
         public Spring spring;
         public Radian yLimitAngle;
         public Radian yLimitAngle;
         public Radian zLimitAngle;
         public Radian zLimitAngle;