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

Added inspectors for colliders and menu items for other various physics objects

BearishSun 9 жил өмнө
parent
commit
981c5231cb

+ 2 - 2
BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -80,8 +80,8 @@ namespace BansheeEngine
 	const WString BuiltinEditorResources::SpriteTextureIconTex = L"SpriteIcon.psd";
 	const WString BuiltinEditorResources::PrefabIconTex = L"PrefabIcon.psd";
 	const WString BuiltinEditorResources::GUISkinIconTex = L"GUISkinIcon.psd";
-	const WString BuiltinEditorResources::PhysicsMaterialIconTex = L"MaterialIcon.psd"; // TODO: Needs proper icon
-	const WString BuiltinEditorResources::PhysicsMeshIconTex = L"MeshIcon.psd"; // TODO: Needs proper icon
+	const WString BuiltinEditorResources::PhysicsMaterialIconTex = L"PhysicsMaterialIcon.psd";
+	const WString BuiltinEditorResources::PhysicsMeshIconTex = L"PhysicsMeshIcon.psd";
 
 	const WString BuiltinEditorResources::ButtonNormalTex = L"ButtonNormal.png";
 	const WString BuiltinEditorResources::ButtonHoverTex = L"ButtonHover.png";

+ 69 - 0
MBansheeEditor/Inspectors/BoxColliderInspector.cs

@@ -0,0 +1,69 @@
+//********************************** 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="BoxCollider"/> component.
+    /// </summary>
+    [CustomInspector(typeof(BoxCollider))]
+    public class BoxColliderInspector : ColliderInspector
+    {
+        private GUIVector3Field centerField = new GUIVector3Field(new LocEdString("Center"));
+        private GUIVector3Field extentsField = new GUIVector3Field(new LocEdString("Extents"));
+
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            BoxCollider collider = InspectedObject as BoxCollider;
+
+            if(collider != null)
+                BuildGUI(collider);
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            BoxCollider collider = InspectedObject as BoxCollider;
+            if (collider == null)
+                return InspectableState.NotModified;
+
+            Refresh(collider);
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Creates GUI elements for fields specific to the box collider.
+        /// </summary>
+        protected void BuildGUI(BoxCollider collider)
+        {
+            centerField.OnChanged += x => { collider.Center = x; MarkAsModified(); };
+            centerField.OnFocusLost += ConfirmModify;
+            centerField.OnConfirmed += ConfirmModify;
+
+            extentsField.OnChanged += x => { collider.Extents = x; MarkAsModified(); };
+            extentsField.OnFocusLost += ConfirmModify;
+            extentsField.OnConfirmed += ConfirmModify;
+
+            base.BuildGUI(collider);
+        }
+
+        /// <summary>
+        /// Updates all GUI elements from current values in the collider.
+        /// </summary>
+        /// <param name="collider">Collider to update the GUI from.</param>
+        protected void Refresh(BoxCollider collider)
+        {
+            centerField.Value = collider.Center;
+            extentsField.Value = collider.Extents;
+
+            base.Refresh(collider);
+        }
+    }
+}

+ 81 - 0
MBansheeEditor/Inspectors/CapsuleColliderInspector.cs

@@ -0,0 +1,81 @@
+//********************************** 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="CapsuleCollider"/> component.
+    /// </summary>
+    [CustomInspector(typeof(CapsuleCollider))]
+    public class CapsuleColliderInspector : ColliderInspector
+    {
+        private GUIVector3Field centerField = new GUIVector3Field(new LocEdString("Center"));
+        private GUIVector3Field normalField = new GUIVector3Field(new LocEdString("Normal"));
+        private GUIFloatField radiusField = new GUIFloatField(new LocEdString("Radius"));
+        private GUIFloatField halfHeightField = new GUIFloatField(new LocEdString("Half height"));
+
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            CapsuleCollider collider = InspectedObject as CapsuleCollider;
+
+            if (collider != null)
+                BuildGUI(collider);
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            CapsuleCollider collider = InspectedObject as CapsuleCollider;
+            if (collider == null)
+                return InspectableState.NotModified;
+
+            Refresh(collider);
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Creates GUI elements for fields specific to the capsule collider.
+        /// </summary>
+        protected void BuildGUI(CapsuleCollider collider)
+        {
+            centerField.OnChanged += x => { collider.Center = x; MarkAsModified(); };
+            centerField.OnFocusLost += ConfirmModify;
+            centerField.OnConfirmed += ConfirmModify;
+
+            normalField.OnChanged += x => { collider.Normal = x; MarkAsModified(); };
+            normalField.OnFocusLost += ConfirmModify;
+            normalField.OnConfirmed += ConfirmModify;
+
+            radiusField.OnChanged += x => { collider.Radius = x; MarkAsModified(); };
+            radiusField.OnFocusLost += ConfirmModify;
+            radiusField.OnConfirmed += ConfirmModify;
+
+            halfHeightField.OnChanged += x => { collider.HalfHeight = x; MarkAsModified(); };
+            halfHeightField.OnFocusLost += ConfirmModify;
+            halfHeightField.OnConfirmed += ConfirmModify;
+
+            base.BuildGUI(collider);
+        }
+
+        /// <summary>
+        /// Updates all GUI elements from current values in the collider.
+        /// </summary>
+        /// <param name="collider">Collider to update the GUI from.</param>
+        protected void Refresh(CapsuleCollider collider)
+        {
+            centerField.Value = collider.Center;
+            normalField.Value = collider.Normal;
+            radiusField.Value = collider.Radius;
+            halfHeightField.Value = collider.HalfHeight;
+
+            base.Refresh(collider);
+        }
+    }
+}

+ 126 - 0
MBansheeEditor/Inspectors/ColliderInspector.cs

@@ -0,0 +1,126 @@
+//********************************** 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="Collider"/> components.
+    /// </summary>
+    public abstract class ColliderInspector : Inspector
+    {
+        private GUIToggleField isTriggerField = new GUIToggleField(new LocEdString("Is trigger"));
+        private GUIFloatField massField = new GUIFloatField(new LocEdString("Mass"));
+        private GUIResourceField materialField = new GUIResourceField(typeof (PhysicsMaterial),
+            new LocEdString("Material"));
+        private GUIFloatField contactOffsetField = new GUIFloatField(new LocEdString("Contact offset"));
+        private GUIFloatField restOffsetField = new GUIFloatField(new LocEdString("Rest offset"));
+
+        private GUIEnumField collisionReportModeField = new GUIEnumField(typeof (CollisionReportMode),
+            new LocEdString("Collision report mode"));
+        private GUIListBoxField layerField = new GUIListBoxField(Layers.Names, false, new LocEdString("Layer"));
+
+        private ulong layersValue = 0;
+        protected InspectableState modifyState;
+
+        /// <summary>
+        /// Updates all GUI elements from current values in the collider.
+        /// </summary>
+        /// <param name="collider">Collider to update the GUI from.</param>
+        protected virtual void Refresh(Collider collider)
+        {
+            isTriggerField.Value = collider.IsTrigger;
+            massField.Value = collider.Mass;
+            materialField.Value = collider.Material;
+            contactOffsetField.Value = collider.ContactOffset;
+            restOffsetField.Value = collider.RestOffset;
+            collisionReportModeField.Value = (ulong)collider.CollisionReportMode;
+
+            if (layersValue != collider.Layer)
+            {
+                bool[] states = new bool[64];
+                for (int i = 0; i < states.Length; i++)
+                    states[i] = (collider.Layer & Layers.Values[i]) == Layers.Values[i];
+
+                layerField.States = states;
+                layersValue = collider.Layer;
+            }
+        }
+
+        /// <summary>
+        /// Creates GUI elements for fields common to all colliders.
+        /// </summary>
+        protected virtual void BuildGUI(Collider collider)
+        {
+            isTriggerField.OnChanged += x => { collider.IsTrigger = x; MarkAsModified(); ConfirmModify(); };
+
+            massField.OnChanged += x => { collider.Mass = x; MarkAsModified(); };
+            massField.OnConfirmed += ConfirmModify;
+            massField.OnFocusLost += ConfirmModify;
+
+            materialField.OnChanged += x =>
+            {
+                PhysicsMaterial mesh = Resources.Load<PhysicsMaterial>(x);
+                collider.Material = mesh;
+
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            contactOffsetField.OnChanged += x => { collider.ContactOffset = x; MarkAsModified(); };
+            contactOffsetField.OnConfirmed += ConfirmModify;
+            contactOffsetField.OnFocusLost += ConfirmModify;
+
+            restOffsetField.OnChanged += x => { collider.RestOffset = x; MarkAsModified(); };
+            restOffsetField.OnConfirmed += ConfirmModify;
+            restOffsetField.OnFocusLost += ConfirmModify;
+
+            collisionReportModeField.OnSelectionChanged += x =>
+            {
+                collider.CollisionReportMode = (CollisionReportMode)x;
+
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            layerField.OnSelectionChanged += x =>
+            {
+                ulong layer = 0;
+                bool[] states = layerField.States;
+                for (int i = 0; i < states.Length; i++)
+                    layer |= states[i] ? Layers.Values[i] : 0;
+
+                layersValue = layer;
+                collider.Layer = layer;
+
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            Layout.AddElement(isTriggerField);
+            Layout.AddElement(massField);
+            Layout.AddElement(materialField);
+            Layout.AddElement(contactOffsetField);
+            Layout.AddElement(restOffsetField);
+            Layout.AddElement(collisionReportModeField);
+            Layout.AddElement(layerField);
+        }
+
+        /// <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;
+        }
+    }
+}

+ 68 - 0
MBansheeEditor/Inspectors/MeshColliderInspector.cs

@@ -0,0 +1,68 @@
+//********************************** 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="MeshCollider"/> component.
+    /// </summary>
+    [CustomInspector(typeof(MeshCollider))]
+    public class MeshColliderInspector : ColliderInspector
+    {
+        private GUIResourceField meshField = new GUIResourceField(typeof(PhysicsMesh), new LocEdString("Mesh"));
+
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            MeshCollider collider = InspectedObject as MeshCollider;
+
+            if (collider != null)
+                BuildGUI(collider);
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            MeshCollider collider = InspectedObject as MeshCollider;
+            if (collider == null)
+                return InspectableState.NotModified;
+
+            Refresh(collider);
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Creates GUI elements for fields specific to the mesh collider.
+        /// </summary>
+        protected void BuildGUI(MeshCollider collider)
+        {
+            meshField.OnChanged += x =>
+            {
+                PhysicsMesh mesh = Resources.Load<PhysicsMesh>(x);
+                collider.Mesh = mesh;
+
+                MarkAsModified();
+                ConfirmModify();
+            };
+
+            base.BuildGUI(collider);
+        }
+
+        /// <summary>
+        /// Updates all GUI elements from current values in the collider.
+        /// </summary>
+        /// <param name="collider">Collider to update the GUI from.</param>
+        protected void Refresh(MeshCollider collider)
+        {
+            meshField.Value = collider.Mesh;
+
+            base.Refresh(collider);
+        }
+    }
+}

+ 69 - 0
MBansheeEditor/Inspectors/PlaneColliderInspector.cs

@@ -0,0 +1,69 @@
+//********************************** 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="PlaneCollider"/> component.
+    /// </summary>
+    [CustomInspector(typeof(PlaneCollider))]
+    public class PlaneColliderInspector : ColliderInspector
+    {
+        private GUIVector3Field normalField = new GUIVector3Field(new LocEdString("Normal"));
+        private GUIFloatField distanceField = new GUIFloatField(new LocEdString("Distance"));
+
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            PlaneCollider collider = InspectedObject as PlaneCollider;
+
+            if (collider != null)
+                BuildGUI(collider);
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            PlaneCollider collider = InspectedObject as PlaneCollider;
+            if (collider == null)
+                return InspectableState.NotModified;
+
+            Refresh(collider);
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Creates GUI elements for fields specific to the plane collider.
+        /// </summary>
+        protected void BuildGUI(PlaneCollider collider)
+        {
+            normalField.OnChanged += x => { collider.Normal = x; MarkAsModified(); };
+            normalField.OnFocusLost += ConfirmModify;
+            normalField.OnConfirmed += ConfirmModify;
+
+            distanceField.OnChanged += x => { collider.Distance = x; MarkAsModified(); };
+            distanceField.OnFocusLost += ConfirmModify;
+            distanceField.OnConfirmed += ConfirmModify;
+
+            base.BuildGUI(collider);
+        }
+
+        /// <summary>
+        /// Updates all GUI elements from current values in the collider.
+        /// </summary>
+        /// <param name="collider">Collider to update the GUI from.</param>
+        protected void Refresh(PlaneCollider collider)
+        {
+            normalField.Value = collider.Normal;
+            distanceField.Value = collider.Distance;
+
+            base.Refresh(collider);
+        }
+    }
+}

+ 69 - 0
MBansheeEditor/Inspectors/SphereColliderInspector.cs

@@ -0,0 +1,69 @@
+//********************************** 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="SphereCollider"/> component.
+    /// </summary>
+    [CustomInspector(typeof(SphereCollider))]
+    public class SphereColliderInspector : ColliderInspector
+    {
+        private GUIVector3Field centerField = new GUIVector3Field(new LocEdString("Center"));
+        private GUIFloatField radiusField = new GUIFloatField(new LocEdString("Radius"));
+
+        /// <inheritdoc/>
+        protected internal override void Initialize()
+        {
+            SphereCollider collider = InspectedObject as SphereCollider;
+
+            if (collider != null)
+                BuildGUI(collider);
+        }
+
+        /// <inheritdoc/>
+        protected internal override InspectableState Refresh()
+        {
+            SphereCollider collider = InspectedObject as SphereCollider;
+            if (collider == null)
+                return InspectableState.NotModified;
+
+            Refresh(collider);
+
+            InspectableState oldState = modifyState;
+            if (modifyState.HasFlag(InspectableState.Modified))
+                modifyState = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Creates GUI elements for fields specific to the sphere collider.
+        /// </summary>
+        protected void BuildGUI(SphereCollider collider)
+        {
+            centerField.OnChanged += x => { collider.Center = x; MarkAsModified(); };
+            centerField.OnFocusLost += ConfirmModify;
+            centerField.OnConfirmed += ConfirmModify;
+
+            radiusField.OnChanged += x => { collider.Radius = x; MarkAsModified(); };
+            radiusField.OnFocusLost += ConfirmModify;
+            radiusField.OnConfirmed += ConfirmModify;
+
+            base.BuildGUI(collider);
+        }
+
+        /// <summary>
+        /// Updates all GUI elements from current values in the collider.
+        /// </summary>
+        /// <param name="collider">Collider to update the GUI from.</param>
+        protected void Refresh(SphereCollider collider)
+        {
+            centerField.Value = collider.Center;
+            radiusField.Value = collider.Radius;
+
+            base.Refresh(collider);
+        }
+    }
+}

+ 14 - 0
MBansheeEditor/Library/LibraryMenu.cs

@@ -22,6 +22,7 @@ namespace BansheeEditor
             entryContextMenu.AddItem("Create", null);
             entryContextMenu.AddItem("Create/Folder", CreateFolder);
             entryContextMenu.AddItem("Create/Material", CreateEmptyMaterial);
+            entryContextMenu.AddItem("Create/Physics material", CreateEmptyPhysicsMaterial);
             entryContextMenu.AddItem("Create/Shader", CreateEmptyShader);
             entryContextMenu.AddItem("Create/C# script", CreateEmptyCSScript);
             entryContextMenu.AddItem("Create/Sprite texture", CreateEmptySpriteTexture);
@@ -154,6 +155,19 @@ namespace BansheeEditor
             LibraryUtility.CreateEmptyStringTable(win.SelectedFolder);
         }
 
+        /// <summary>
+        /// Creates a new physics material with the default properties in the currently selected project library folder.
+        /// </summary>
+        [MenuItem("Resources/Create/Physics material", 9044, false, "IsLibraryWindowActive")]
+        internal static void CreateEmptyPhysicsMaterial()
+        {
+            LibraryWindow win = EditorWindow.GetWindow<LibraryWindow>();
+            if (win == null)
+                return;
+
+            LibraryUtility.CreateEmptyPhysicsMaterial(win.SelectedFolder);
+        }
+
         /// <summary>
         /// Opens the currently selected project library file or folder in the default external application.
         /// </summary>

+ 13 - 0
MBansheeEditor/Library/LibraryUtility.cs

@@ -103,6 +103,19 @@ namespace BansheeEditor
             ProjectLibrary.Refresh(path);
         }
 
+        /// <summary>
+        /// Creates a new physics material with the default properties in the specified folder.
+        /// </summary>
+        /// <param name="folder">Folder relative to project library to create the material in.</param>
+        public static void CreateEmptyPhysicsMaterial(string folder)
+        {
+            string path = Path.Combine(folder, "New Physics Material.asset");
+            path = GetUniquePath(path);
+
+            PhysicsMaterial material = new PhysicsMaterial();
+            ProjectLibrary.Create(material, path);
+        }
+
         /// <summary>
         /// Checks if a file or folder at the specified path exists in the library, and if it does generates a new unique 
         /// name for the file or folder.

+ 6 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -47,9 +47,15 @@
     <Compile Include="CodeEditor.cs" />
     <Compile Include="ColorPicker.cs" />
     <Compile Include="EditorPersistentData.cs" />
+    <Compile Include="Inspectors\BoxColliderInspector.cs" />
+    <Compile Include="Inspectors\CapsuleColliderInspector.cs" />
+    <Compile Include="Inspectors\ColliderInspector.cs" />
     <Compile Include="Inspectors\GUIWidgetInspector.cs" />
+    <Compile Include="Inspectors\MeshColliderInspector.cs" />
     <Compile Include="Inspectors\PhysicsMaterialInspector.cs" />
     <Compile Include="Inspectors\PhysicsMeshInspector.cs" />
+    <Compile Include="Inspectors\PlaneColliderInspector.cs" />
+    <Compile Include="Inspectors\SphereColliderInspector.cs" />
     <Compile Include="LogWindow.cs" />
     <Compile Include="DefaultSize.cs" />
     <Compile Include="DialogBox.cs" />

+ 195 - 4
MBansheeEditor/MenuItems.cs

@@ -1,10 +1,6 @@
 //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using BansheeEngine;
 
 namespace BansheeEditor
@@ -109,6 +105,201 @@ namespace BansheeEditor
             EditorApplication.SetSceneDirty();
         }
 
+        /// <summary>
+        /// Adds a BoxCollider component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Box collider", 7044)]
+        private static void AddBoxCollider()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("BoxCollider", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a BoxCollider component");
+            so.AddComponent<BoxCollider>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a SphereCollider component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Sphere collider", 7043)]
+        private static void AddSphereCollider()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("SphereCollider", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a SphereCollider component");
+            so.AddComponent<SphereCollider>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a CapsuleCollider component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Capsule collider", 7042)]
+        private static void AddCapsuleCollider()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("CapsuleCollider", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a CapsuleCollider component");
+            so.AddComponent<CapsuleCollider>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a MeshCollider component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Mesh collider", 7041)]
+        private static void AddMeshCollider()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("MeshCollider", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a MeshCollider component");
+            so.AddComponent<MeshCollider>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a PlaneCollider component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Plane collider", 7040)]
+        private static void AddPlaneCollider()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("PlaneCollider", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a PlaneCollider component");
+            so.AddComponent<PlaneCollider>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a Rigidbody component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Rigidbody", 7039, true)]
+        private static void AddRigidbody()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("Rigidbody", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a Rigidbody component");
+            so.AddComponent<Rigidbody>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a CharacterController component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Character controller", 7038)]
+        private static void AddCharacterController()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("CharacterController", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a CharacterController component");
+            so.AddComponent<CharacterController>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a FixedJoint component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Fixed joint", 7037, true)]
+        private static void AddFixedJoint()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("FixedJoint", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a FixedJoint component");
+            so.AddComponent<FixedJoint>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a DistanceJoint component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Distance joint", 7036)]
+        private static void AddDistanceJoint()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("DistanceJoint", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a DistanceJoint component");
+            so.AddComponent<DistanceJoint>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a HingeJoint component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Hinge joint", 7035)]
+        private static void AddHingeJoint()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("HingeJoint", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a HingeJoint component");
+            so.AddComponent<HingeJoint>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a SphericalJoint component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Spherical joint", 7034)]
+        private static void AddSphericalJoint()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("SphericalJoint", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a SphericalJoint component");
+            so.AddComponent<SphericalJoint>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a SliderJoint component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/Slider joint", 7032)]
+        private static void AddSliderJoint()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("SliderJoint", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a SliderJoint component");
+            so.AddComponent<SliderJoint>();
+            EditorApplication.SetSceneDirty();
+        }
+
+        /// <summary>
+        /// Adds a D6Joint component to the currently selected scene object.
+        /// </summary>
+        [MenuItem("Components/Physics/D6 joint", 7032)]
+        private static void AddD6Joint()
+        {
+            SceneObject so = Selection.SceneObject;
+            if (so == null)
+                so = UndoRedo.CreateSO("D6Joint", "New scene object");
+
+            UndoRedo.RecordSO(so, false, "Added a D6Joint component");
+            so.AddComponent<D6Joint>();
+            EditorApplication.SetSceneDirty();
+        }
+
         /// <summary>
         /// Creates a new empty scene object.
         /// </summary>

+ 2 - 4
MBansheeEditor/UndoRedo.cs

@@ -2,16 +2,14 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 using System;
 using System.Collections.Generic;
-using System.Linq;
 using System.Runtime.CompilerServices;
-using System.Text;
-using System.Threading.Tasks;
 using BansheeEngine;
 
 namespace BansheeEditor
 {
     /// <summary>
-    /// Provides functionality to undo or redo recently performed operations in the editor.
+    /// Provides functionality to undo or redo recently performed operations in the editor. All commands executed from this
+    /// class are undoable/redoable.
     /// </summary>
     public static class UndoRedo
     {

+ 4 - 4
MBansheeEngine/Physics/MeshCollider.cs

@@ -55,10 +55,10 @@ namespace BansheeEngine
 		    return mesh == null|| mesh.MeshType == PhysicsMeshType.Convex || parent.Kinematic;
         }
 
-    /// <summary>
-    /// Returns the native mesh collider wrapped by this component.
-    /// </summary>
-    private NativeMeshCollider Native
+        /// <summary>
+        /// Returns the native mesh collider wrapped by this component.
+        /// </summary>
+        private NativeMeshCollider Native
         {
             get { return (NativeMeshCollider)native; }
         }

+ 1 - 1
MBansheeEngine/ResourceRef.cs

@@ -17,7 +17,7 @@ namespace BansheeEngine
         { }
 
         /// <summary>
-        /// Checks is the referenced resource loaded
+        /// Checks is the referenced resource loaded.
         /// </summary>
         public bool IsLoaded
         {