2
0
BearishSun 10 жил өмнө
parent
commit
153a11a96e

+ 42 - 2
BansheeEditor/Source/BsSelection.cpp

@@ -113,7 +113,27 @@ namespace BansheeEngine
 		GUISceneTreeView* sceneTreeView = SceneTreeViewLocator::instance();
 		GUISceneTreeView* sceneTreeView = SceneTreeViewLocator::instance();
 		if (sceneTreeView != nullptr)
 		if (sceneTreeView != nullptr)
 		{
 		{
-			mSelectedSceneObjects = sceneTreeView->getSelection();
+			Vector<HSceneObject> newSelection = sceneTreeView->getSelection();
+
+			bool isDirty = newSelection.size() != mSelectedSceneObjects.size();
+			if (!isDirty)
+			{
+				UINT32 count = (UINT32)newSelection.size();
+
+				for (UINT32 i = 0; i < count; i++)
+				{
+					if (newSelection[i] != mSelectedSceneObjects[i])
+					{
+						isDirty = true;
+						break;
+					}
+				}
+			}
+
+			if (!isDirty)
+				return;
+
+			mSelectedSceneObjects = newSelection;
 			mSelectedResourcePaths.clear();
 			mSelectedResourcePaths.clear();
 
 
 			onSelectionChanged(mSelectedSceneObjects, Vector<Path>());
 			onSelectionChanged(mSelectedSceneObjects, Vector<Path>());
@@ -125,7 +145,27 @@ namespace BansheeEngine
 		GUIResourceTreeView* resourceTreeView = ResourceTreeViewLocator::instance();
 		GUIResourceTreeView* resourceTreeView = ResourceTreeViewLocator::instance();
 		if (resourceTreeView != nullptr)
 		if (resourceTreeView != nullptr)
 		{
 		{
-			mSelectedResourcePaths = resourceTreeView->getSelection();
+			Vector<Path> newSelection = resourceTreeView->getSelection();
+
+			bool isDirty = newSelection.size() != mSelectedResourcePaths.size();
+			if (!isDirty)
+			{
+				UINT32 count = (UINT32)newSelection.size();
+
+				for (UINT32 i = 0; i < count; i++)
+				{
+					if (newSelection[i] != mSelectedResourcePaths[i])
+					{
+						isDirty = true;
+						break;
+					}
+				}
+			}
+
+			if (!isDirty)
+				return;
+
+			mSelectedResourcePaths = newSelection;
 			mSelectedSceneObjects.clear();
 			mSelectedSceneObjects.clear();
 
 
 			onSelectionChanged(Vector<HSceneObject>(), mSelectedResourcePaths);
 			onSelectionChanged(Vector<HSceneObject>(), mSelectedResourcePaths);

+ 26 - 3
MBansheeEditor/Inspector/InspectorWindow.cs

@@ -46,12 +46,12 @@ namespace BansheeEditor
         }
         }
 
 
         private static readonly Color HIGHLIGHT_COLOR = new Color(1.0f, 1.0f, 1.0f, 0.5f);
         private static readonly Color HIGHLIGHT_COLOR = new Color(1.0f, 1.0f, 1.0f, 0.5f);
+        private const int RESOURCE_TITLE_HEIGHT = 30;
 
 
         private List<InspectorComponent> inspectorComponents = new List<InspectorComponent>();
         private List<InspectorComponent> inspectorComponents = new List<InspectorComponent>();
         private InspectorResource inspectorResource;
         private InspectorResource inspectorResource;
         private GUIScrollArea inspectorScrollArea;
         private GUIScrollArea inspectorScrollArea;
         private GUILayout inspectorLayout;
         private GUILayout inspectorLayout;
-        private GUILayoutY sceneObjectLayout;
         private GUIPanel highlightPanel;
         private GUIPanel highlightPanel;
         private GUITexture scrollAreaHighlight;
         private GUITexture scrollAreaHighlight;
 
 
@@ -109,6 +109,30 @@ namespace BansheeEditor
             GUI.AddElement(inspectorScrollArea);
             GUI.AddElement(inspectorScrollArea);
             inspectorLayout = inspectorScrollArea.Layout;
             inspectorLayout = inspectorScrollArea.Layout;
 
 
+            GUIPanel titlePanel = inspectorLayout.AddPanel();
+            titlePanel.SetHeight(RESOURCE_TITLE_HEIGHT);
+
+            GUILayoutY titleLayout = titlePanel.AddLayoutY();
+            titleLayout.SetPosition(5, 5);
+
+            string name = Path.GetFileNameWithoutExtension(resourcePath);
+            string type = activeResource.GetType().Name;
+
+            LocString title = new LocEdString(name + " (" + type + ")");
+            GUILabel titleLabel = new GUILabel(title);
+
+            titleLayout.AddFlexibleSpace();
+            GUILayoutX titleLabelLayout = titleLayout.AddLayoutX();
+            titleLabelLayout.AddElement(titleLabel);
+            titleLayout.AddFlexibleSpace();
+
+            GUIPanel titleBgPanel = titlePanel.AddPanel(1);
+
+            GUITexture titleBg = new GUITexture(null, EditorStyles.InspectorTitleBg);
+            titleBgPanel.AddElement(titleBg);
+
+            inspectorLayout.AddSpace(5);
+
             inspectorResource = new InspectorResource();
             inspectorResource = new InspectorResource();
             inspectorResource.panel = inspectorLayout.AddPanel();
             inspectorResource.panel = inspectorLayout.AddPanel();
 
 
@@ -188,7 +212,7 @@ namespace BansheeEditor
             GUIPanel sceneObjectPanel = inspectorLayout.AddPanel();
             GUIPanel sceneObjectPanel = inspectorLayout.AddPanel();
             sceneObjectPanel.SetHeight(GetTitleBounds().height);
             sceneObjectPanel.SetHeight(GetTitleBounds().height);
 
 
-            sceneObjectLayout = sceneObjectPanel.AddLayoutY();
+            GUILayoutY sceneObjectLayout = sceneObjectPanel.AddLayoutY();
             sceneObjectLayout.SetPosition(5, 5);
             sceneObjectLayout.SetPosition(5, 5);
 
 
             GUIPanel sceneObjectBgPanel = sceneObjectPanel.AddPanel(1);
             GUIPanel sceneObjectBgPanel = sceneObjectPanel.AddPanel(1);
@@ -583,7 +607,6 @@ namespace BansheeEditor
             soScaleY = null;
             soScaleY = null;
             soScaleZ = null;
             soScaleZ = null;
             dropBounds = new Rect2I();
             dropBounds = new Rect2I();
-            sceneObjectLayout = null;
 
 
             activeResource = null;
             activeResource = null;
             currentType = InspectorType.None;
             currentType = InspectorType.None;

+ 637 - 0
MBansheeEditor/Inspectors/MaterialInspector.cs

@@ -0,0 +1,637 @@
+using System.Collections.Generic;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Renders an inspector for the <see cref="Material"/> resource.
+    /// </summary>
+    [CustomInspector(typeof(Material))]
+    internal class MaterialInspector : Inspector
+    {
+        private MaterialParamGUI[] guiParams;
+        private GUIResourceField shaderField;
+        private bool isInitialized;
+
+        /// <summary>
+        /// Recreates GUI elements for all material parameters.
+        /// </summary>
+        /// <param name="material">Material to create parameters for</param>
+        private void RebuildParamGUI(Material material)
+        {
+            if (guiParams != null)
+            {
+                foreach (var param in guiParams)
+                    param.Destroy();
+
+                guiParams = null;
+            }
+
+            if (material != null && material.Shader != null)
+                guiParams = CreateMaterialGUI(material, layout);
+        }
+
+        /// <inheritdoc/>
+        internal override bool Refresh()
+        {
+            Material material = referencedObject as Material;
+            if (material == null)
+                return false;
+
+            if (!isInitialized)
+            {
+                shaderField = new GUIResourceField(typeof(Shader), new LocEdString("Shader"));
+                shaderField.OnChanged += (x) =>
+                {
+                    material.Shader = x as Shader;
+                    RebuildParamGUI(material);
+                };
+
+                layout.AddElement(shaderField);
+
+                RebuildParamGUI(material);
+                isInitialized = true;
+            }
+
+            bool anythingModified = false;
+
+            if (material.Shader != shaderField.Value)
+            {
+                shaderField.Value = material.Shader;
+                RebuildParamGUI(material);
+                anythingModified = true;
+            }
+
+            if (guiParams != null)
+            {
+                foreach (var param in guiParams)
+                    anythingModified |= param.Refresh(material);
+            }
+
+            return anythingModified;
+        }
+
+        /// <summary>
+        /// Creates a set of objects in which each object represents a GUI for a material parameter.
+        /// </summary>
+        /// <param name="mat">Material for whose parameters to create GUI for.</param>
+        /// <param name="layout">Layout to add the parameter GUI elements to.</param>
+        /// <returns>A material parameter GUI object for each supported material parameter.</returns>
+        static internal MaterialParamGUI[] CreateMaterialGUI(Material mat, GUILayout layout)
+        {
+            Shader shader = mat.Shader;
+            if (shader == null)
+                return new MaterialParamGUI[0];
+
+            List<MaterialParamGUI> guiParams = new List<MaterialParamGUI>();
+            ShaderParameter[] shaderParams = shader.Parameters;
+
+            foreach (var param in shaderParams)
+            {
+                switch (param.type)
+                {
+                    case ShaderParameterType.Float:
+                        guiParams.Add(new MaterialParamFloatGUI(param, mat, layout));
+                        break;
+                    case ShaderParameterType.Vector2:
+                        guiParams.Add(new MaterialParamVec2GUI(param, mat, layout));
+                        break;
+                    case ShaderParameterType.Vector3:
+                        guiParams.Add(new MaterialParamVec3GUI(param, mat, layout));
+                        break;
+                    case ShaderParameterType.Vector4:
+                        guiParams.Add(new MaterialParamVec4GUI(param, mat, layout));
+                        break;
+                    case ShaderParameterType.Matrix3:
+                        guiParams.Add(new MaterialParamMat3GUI(param, mat, layout));
+                        break;
+                    case ShaderParameterType.Matrix4:
+                        guiParams.Add(new MaterialParamMat4GUI(param, mat, layout));
+                        break;
+                    case ShaderParameterType.Color:
+                        guiParams.Add(new MaterialParamColorGUI(param, mat, layout));
+                        break;
+                    case ShaderParameterType.Texture2D:
+                    case ShaderParameterType.Texture3D:
+                    case ShaderParameterType.TextureCube:
+                        guiParams.Add(new MaterialParamTextureGUI(param, mat, layout));
+                        break;
+                }
+            }
+
+            return guiParams.ToArray();
+        }
+    }
+
+    /// <summary>
+    /// Contains GUI element(s) for a single parameter in a <see cref="Material"/>.
+    /// </summary>
+    internal abstract class MaterialParamGUI
+    {
+        protected ShaderParameter shaderParam;
+
+        /// <summary>
+        /// Creates a new material parameter GUI.
+        /// </summary>
+        /// <param name="shaderParam">Shader parameter to create the GUI for.</param>
+        protected MaterialParamGUI(ShaderParameter shaderParam)
+        {
+            this.shaderParam = shaderParam;
+        }
+
+        /// <summary>
+        /// Checks if the data stored in GUI and in the material matches, and updates the GUI if it doesn't.
+        /// </summary>
+        /// <param name="material">Material whose data to check.</param>
+        /// <returns>True if anything was modified, false otherwise.</returns>
+        internal abstract bool Refresh(Material material);
+
+        /// <summary> 
+        /// Destroys the internal GUI elements.
+        /// </summary>
+        internal abstract void Destroy();
+    }
+
+    /// <summary>
+    /// Contains GUI element(s) for a single floating point parameter in a <see cref="Material"/>.
+    /// </summary>
+    internal class MaterialParamFloatGUI : MaterialParamGUI
+    {
+        private GUIFloatField guiElem;
+
+        /// <summary>
+        /// Creates a new material parameter GUI.
+        /// </summary>
+        /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of floating point type.</param>
+        /// <param name="material">Material the parameter is a part of.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        internal MaterialParamFloatGUI(ShaderParameter shaderParam, Material material, GUILayout layout)
+            : base(shaderParam)
+        {
+            LocString title = new LocEdString(shaderParam.name);
+            guiElem = new GUIFloatField(title);
+            guiElem.OnChanged += (x) =>
+            {
+                material.SetFloat(shaderParam.name, x);
+            };
+
+            layout.AddElement(guiElem);
+        }
+
+        /// <inheritdoc/>
+        internal override bool Refresh(Material material)
+        {
+            float value = material.GetFloat(shaderParam.name);
+            if (value != guiElem.Value)
+            {
+                guiElem.Value = value;
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        internal override void Destroy()
+        {
+            guiElem.Destroy();
+        }
+    }
+
+    /// <summary>
+    /// Contains GUI element(s) for a single 2D vector parameter in a <see cref="Material"/>.
+    /// </summary>
+    internal class MaterialParamVec2GUI : MaterialParamGUI
+    {
+        private GUIVector2Field guiElem;
+
+        /// <summary>
+        /// Creates a new material parameter GUI.
+        /// </summary>
+        /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 2D vector type.</param>
+        /// <param name="material">Material the parameter is a part of.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        internal MaterialParamVec2GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
+            : base(shaderParam)
+        {
+            LocString title = new LocEdString(shaderParam.name);
+            guiElem = new GUIVector2Field(title);
+            guiElem.OnChanged += (x) =>
+            {
+                material.SetVector2(shaderParam.name, x);
+            };
+
+            layout.AddElement(guiElem);
+        }
+
+        /// <inheritdoc/>
+        internal override bool Refresh(Material material)
+        {
+            Vector2 value = material.GetVector2(shaderParam.name);
+            if (value != guiElem.Value)
+            {
+                guiElem.Value = value;
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        internal override void Destroy()
+        {
+            guiElem.Destroy();
+        }
+    }
+
+    /// <summary>
+    /// Contains GUI element(s) for a single 3D vector parameter in a <see cref="Material"/>.
+    /// </summary>
+    internal class MaterialParamVec3GUI : MaterialParamGUI
+    {
+        private GUIVector3Field guiElem;
+
+        /// <summary>
+        /// Creates a new material parameter GUI.
+        /// </summary>
+        /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 3D vector type.</param>
+        /// <param name="material">Material the parameter is a part of.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        internal MaterialParamVec3GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
+            : base(shaderParam)
+        {
+            LocString title = new LocEdString(shaderParam.name);
+            guiElem = new GUIVector3Field(title);
+            guiElem.OnChanged += (x) =>
+            {
+                material.SetVector3(shaderParam.name, x);
+            };
+
+            layout.AddElement(guiElem);
+        }
+
+        /// <inheritdoc/>
+        internal override bool Refresh(Material material)
+        {
+            Vector3 value = material.GetVector3(shaderParam.name);
+            if (value != guiElem.Value)
+            {
+                guiElem.Value = value;
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        internal override void Destroy()
+        {
+            guiElem.Destroy();
+        }
+    }
+
+    /// <summary>
+    /// Contains GUI element(s) for a single 4D vector parameter in a <see cref="Material"/>.
+    /// </summary>
+    internal class MaterialParamVec4GUI : MaterialParamGUI
+    {
+        private GUIVector4Field guiElem;
+
+        /// <summary>
+        /// Creates a new material parameter GUI.
+        /// </summary>
+        /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 4D vector type.</param>
+        /// <param name="material">Material the parameter is a part of.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        internal MaterialParamVec4GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
+            : base(shaderParam)
+        {
+            LocString title = new LocEdString(shaderParam.name);
+            guiElem = new GUIVector4Field(title);
+            guiElem.OnChanged += (x) =>
+            {
+                material.SetVector4(shaderParam.name, x);
+            };
+
+            layout.AddElement(guiElem);
+        }
+
+        /// <inheritdoc/>
+        internal override bool Refresh(Material material)
+        {
+            Vector4 value = material.GetVector4(shaderParam.name);
+            if (value != guiElem.Value)
+            {
+                guiElem.Value = value;
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        internal override void Destroy()
+        {
+            guiElem.Destroy();
+        }
+    }
+
+    /// <summary>
+    /// Contains GUI element(s) for a single 3x3 matrix parameter in a <see cref="Material"/>.
+    /// </summary>
+    internal class MaterialParamMat3GUI : MaterialParamGUI
+    {
+        private const int MAT_SIZE = 3;
+
+        private GUIFloatField[] guiMatFields = new GUIFloatField[MAT_SIZE * MAT_SIZE];
+
+        /// <summary>
+        /// Creates a new material parameter GUI.
+        /// </summary>
+        /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 3x3 matrix type.</param>
+        /// <param name="material">Material the parameter is a part of.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        internal MaterialParamMat3GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
+            : base(shaderParam)
+        {
+            LocString title = new LocEdString(shaderParam.name);
+            GUILabel guiTitle = new GUILabel(title, GUIOption.FixedWidth(100));
+
+            GUILayout mainLayout = layout.AddLayoutX();
+            mainLayout.AddElement(guiTitle);
+
+            GUILayoutY contentLayout = mainLayout.AddLayoutY();
+
+            GUILayoutX[] rows = new GUILayoutX[MAT_SIZE];
+            for (int i = 0; i < MAT_SIZE; i++)
+                rows[i] = contentLayout.AddLayoutX();
+
+            for (int row = 0; row < MAT_SIZE; row++)
+            {
+                for (int col = 0; col < MAT_SIZE; col++)
+                {
+                    int index = row * MAT_SIZE + col;
+                    guiMatFields[index] = new GUIFloatField(row + ", " + col, 30);
+
+                    GUIFloatField field = guiMatFields[index];
+                    rows[row].AddElement(field);
+
+                    int hoistedRow = row;
+                    int hoistedCol = col;
+                    field.OnChanged += (x) =>
+                    {
+                        Matrix3 value = material.GetMatrix3(shaderParam.name);
+                        value[hoistedRow, hoistedCol] = x;
+                        material.SetMatrix3(shaderParam.name, value);
+                    };
+                }
+            }
+        }
+
+        /// <inheritdoc/>
+        internal override bool Refresh(Material material)
+        {
+            Matrix3 value = material.GetMatrix3(shaderParam.name);
+
+            bool wasModified = false;
+            for (int row = 0; row < MAT_SIZE; row++)
+            {
+                for (int col = 0; col < MAT_SIZE; col++)
+                {
+                    int index = row * MAT_SIZE + col;
+                    if (value[row, col] != guiMatFields[index].Value)
+                    {
+                        guiMatFields[index].Value = value[row, col];
+                        wasModified = true;
+                    }
+                }
+            }
+
+            return wasModified;
+        }
+
+        /// <inheritdoc/>
+        internal override void Destroy()
+        {
+            for (int row = 0; row < MAT_SIZE; row++)
+            {
+                for (int col = 0; col < MAT_SIZE; col++)
+                {
+                    int index = row*MAT_SIZE + col;
+                    guiMatFields[index].Destroy();
+                }
+            }
+        }
+    }
+
+    /// <summary>
+    /// Contains GUI element(s) for a single 4x4 matrix parameter in a <see cref="Material"/>.
+    /// </summary>
+    internal class MaterialParamMat4GUI : MaterialParamGUI
+    {
+        private const int MAT_SIZE = 4;
+
+        private GUIFloatField[] guiMatFields = new GUIFloatField[MAT_SIZE * MAT_SIZE];
+
+        /// <summary>
+        /// Creates a new material parameter GUI.
+        /// </summary>
+        /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 4x4 matrix type.</param>
+        /// <param name="material">Material the parameter is a part of.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        internal MaterialParamMat4GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
+            : base(shaderParam)
+        {
+            LocString title = new LocEdString(shaderParam.name);
+            GUILabel guiTitle = new GUILabel(title, GUIOption.FixedWidth(100));
+
+            GUILayout mainLayout = layout.AddLayoutX();
+            mainLayout.AddElement(guiTitle);
+
+            GUILayoutY contentLayout = mainLayout.AddLayoutY();
+
+            GUILayoutX[] rows = new GUILayoutX[MAT_SIZE];
+            for (int i = 0; i < MAT_SIZE; i++)
+                rows[i] = contentLayout.AddLayoutX();
+
+            for (int row = 0; row < MAT_SIZE; row++)
+            {
+                for (int col = 0; col < MAT_SIZE; col++)
+                {
+                    int index = row * MAT_SIZE + col;
+                    guiMatFields[index] = new GUIFloatField(row + ", " + col, 30);
+
+                    GUIFloatField field = guiMatFields[index];
+                    rows[row].AddElement(field);
+
+                    int hoistedRow = row;
+                    int hoistedCol = col;
+                    field.OnChanged += (x) =>
+                    {
+                        Matrix4 value = material.GetMatrix4(shaderParam.name);
+                        value[hoistedRow, hoistedCol] = x;
+                        material.SetMatrix4(shaderParam.name, value);
+                    };
+                }
+            }
+        }
+
+        /// <inheritdoc/>
+        internal override bool Refresh(Material material)
+        {
+            Matrix4 value = material.GetMatrix4(shaderParam.name);
+
+            bool wasModified = false;
+            for (int row = 0; row < MAT_SIZE; row++)
+            {
+                for (int col = 0; col < MAT_SIZE; col++)
+                {
+                    int index = row * MAT_SIZE + col;
+                    if (value[row, col] != guiMatFields[index].Value)
+                    {
+                        guiMatFields[index].Value = value[row, col];
+                        wasModified = true;
+                    }
+                }
+            }
+
+            return wasModified;
+        }
+
+        /// <inheritdoc/>
+        internal override void Destroy()
+        {
+            for (int row = 0; row < MAT_SIZE; row++)
+            {
+                for (int col = 0; col < MAT_SIZE; col++)
+                {
+                    int index = row * MAT_SIZE + col;
+                    guiMatFields[index].Destroy();
+                }
+            }
+        }
+    }
+
+    /// <summary>
+    /// Contains GUI element(s) for a single color parameter in a <see cref="Material"/>.
+    /// </summary>
+    internal class MaterialParamColorGUI : MaterialParamGUI
+    {
+        private GUIColorField guiElem;
+
+        /// <summary>
+        /// Creates a new material parameter GUI.
+        /// </summary>
+        /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of color type.</param>
+        /// <param name="material">Material the parameter is a part of.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        internal MaterialParamColorGUI(ShaderParameter shaderParam, Material material, GUILayout layout)
+            : base(shaderParam)
+        {
+            LocString title = new LocEdString(shaderParam.name);
+            guiElem = new GUIColorField(title);
+            guiElem.OnChanged += (x) =>
+            {
+                material.SetColor(shaderParam.name, x);
+            };
+
+            layout.AddElement(guiElem);
+        }
+
+        /// <inheritdoc/>
+        internal override bool Refresh(Material material)
+        {
+            Color value = material.GetColor(shaderParam.name);
+            if (value != guiElem.Value)
+            {
+                guiElem.Value = value;
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        internal override void Destroy()
+        {
+            guiElem.Destroy();
+        }
+    }
+
+    /// <summary>
+    /// Contains GUI element(s) for a single texture parameter in a <see cref="Material"/>.
+    /// </summary>
+    internal class MaterialParamTextureGUI : MaterialParamGUI
+    {
+        private GUITextureField guiElem;
+
+        /// <summary>
+        /// Creates a new material parameter GUI.
+        /// </summary>
+        /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of texture type.</param>
+        /// <param name="material">Material the parameter is a part of.</param>
+        /// <param name="layout">Layout to append the GUI elements to.</param>
+        internal MaterialParamTextureGUI(ShaderParameter shaderParam, Material material, GUILayout layout)
+            : base(shaderParam)
+        {
+            LocString title = new LocEdString(shaderParam.name);
+            guiElem = new GUITextureField(title);
+
+            switch (shaderParam.type)
+            {
+                case ShaderParameterType.Texture2D:
+                    guiElem.OnChanged += (x) =>
+                    {
+                        material.SetTexture2D(shaderParam.name, x as Texture2D);
+                    };
+                    break;
+                case ShaderParameterType.Texture3D:
+                    guiElem.OnChanged += (x) =>
+                    {
+                        material.SetTexture3D(shaderParam.name, x as Texture3D);
+                    };
+                    break;
+                case ShaderParameterType.TextureCube:
+                    guiElem.OnChanged += (x) =>
+                    {
+                        material.SetTextureCube(shaderParam.name, x as TextureCube);
+                    };
+                    break;
+            }
+
+            layout.AddElement(guiElem);
+        }
+
+        /// <inheritdoc/>
+        internal override bool Refresh(Material material)
+        {
+            Texture value = null;
+            switch (shaderParam.type)
+            {
+                case ShaderParameterType.Texture2D:
+                    value = material.GetTexture2D(shaderParam.name);
+                    break;
+                case ShaderParameterType.Texture3D:
+                    value = material.GetTexture3D(shaderParam.name);
+                    break;
+                case ShaderParameterType.TextureCube:
+                    value = material.GetTextureCube(shaderParam.name);
+                    break;
+            }
+
+            if (value != guiElem.Value)
+            {
+                guiElem.Value = value;
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <inheritdoc/>
+        internal override void Destroy()
+        {
+            guiElem.Destroy();
+        }
+    }
+}

+ 3 - 0
MBansheeEditor/Library/LibraryWindow.cs

@@ -20,6 +20,9 @@ namespace BansheeEditor
     /// </summary>
     /// </summary>
     internal sealed class LibraryWindow : EditorWindow
     internal sealed class LibraryWindow : EditorWindow
     {
     {
+        /// <summary>
+        /// Directions the selection cursor in library window can be moved in.
+        /// </summary>
         internal enum MoveDirection
         internal enum MoveDirection
         {
         {
             Up, Down, Left, Right
             Up, Down, Left, Right

+ 1 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -54,6 +54,7 @@
     <Compile Include="GUI\TextureField.cs" />
     <Compile Include="GUI\TextureField.cs" />
     <Compile Include="HierarchyWindow.cs" />
     <Compile Include="HierarchyWindow.cs" />
     <Compile Include="Inspectors\CameraInspector.cs" />
     <Compile Include="Inspectors\CameraInspector.cs" />
+    <Compile Include="Inspectors\MaterialInspector.cs" />
     <Compile Include="Inspector\InspectorUtility.cs" />
     <Compile Include="Inspector\InspectorUtility.cs" />
     <Compile Include="Library\LibraryGUIContent.cs" />
     <Compile Include="Library\LibraryGUIContent.cs" />
     <Compile Include="Library\LibraryDropDown.cs" />
     <Compile Include="Library\LibraryDropDown.cs" />

+ 2 - 2
SBansheeEditor/Source/BsScriptInspectorUtility.cpp

@@ -6,7 +6,7 @@
 #include "BsMonoUtil.h"
 #include "BsMonoUtil.h"
 #include "BsScriptAssemblyManager.h"
 #include "BsScriptAssemblyManager.h"
 #include "BsScriptObjectManager.h"
 #include "BsScriptObjectManager.h"
-#include "BsScriptManagedResource.h"
+#include "BsScriptResource.h"
 #include "BsScriptComponent.h"
 #include "BsScriptComponent.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
@@ -89,7 +89,7 @@ namespace BansheeEngine
 
 
 				if (curClass->isSubClassOf(inspectorClass))
 				if (curClass->isSubClassOf(inspectorClass))
 				{
 				{
-					bool isValidInspectorType = referencedClass->isSubClassOf(ScriptManagedResource::getMetaData()->scriptClass) ||
+					bool isValidInspectorType = referencedClass->isSubClassOf(ScriptResource::getMetaData()->scriptClass) ||
 						referencedClass->isSubClassOf(ScriptComponent::getMetaData()->scriptClass);
 						referencedClass->isSubClassOf(ScriptComponent::getMetaData()->scriptClass);
 
 
 					if (!isValidInspectorType)
 					if (!isValidInspectorType)

+ 1 - 1
SBansheeEditor/Source/BsScriptSelection.cpp

@@ -194,7 +194,7 @@ namespace BansheeEngine
 		UINT32 numPaths = (UINT32)resPaths.size();
 		UINT32 numPaths = (UINT32)resPaths.size();
 		ScriptArray scriptPaths = ScriptArray::create<String>(numPaths);
 		ScriptArray scriptPaths = ScriptArray::create<String>(numPaths);
 		for (UINT32 i = 0; i < numPaths; i++)
 		for (UINT32 i = 0; i < numPaths; i++)
-			scriptObjects.set(i, resPaths[i].toString());
+			scriptPaths.set(i, resPaths[i].toString());
 
 
 		MonoArray* monoObjects = scriptObjects.getInternal();
 		MonoArray* monoObjects = scriptObjects.getInternal();
 		MonoArray* monoPaths = scriptPaths.getInternal();
 		MonoArray* monoPaths = scriptPaths.getInternal();

+ 22 - 21
SBansheeEngine/Source/BsScriptSerializableObject.cpp

@@ -61,42 +61,43 @@ namespace BansheeEngine
 
 
 		ScriptSerializableObject* nativeInstance = new (bs_alloc<ScriptSerializableObject>()) ScriptSerializableObject(instance, typeInfo);
 		ScriptSerializableObject* nativeInstance = new (bs_alloc<ScriptSerializableObject>()) ScriptSerializableObject(instance, typeInfo);
 
 
+		Vector<ManagedSerializableFieldInfoPtr> sortedFields;
+		
 		if(objInfo != nullptr)
 		if(objInfo != nullptr)
 		{
 		{
-			::MonoClass* serializableFieldClass = ScriptSerializableField::getMetaData()->scriptClass->_getInternalClass();
-
-			MonoArray* serializableFieldArray = mono_array_new(MonoManager::instance().getDomain(), 
-				serializableFieldClass, (UINT32)objInfo->mFields.size());
-
-			Vector<ManagedSerializableFieldInfoPtr> sortedFields((UINT32)objInfo->mFields.size());
+			sortedFields.resize(objInfo->mFields.size());
 			UINT32 i = 0;
 			UINT32 i = 0;
 			for (auto& fieldPair : objInfo->mFields)
 			for (auto& fieldPair : objInfo->mFields)
 			{
 			{
 				sortedFields[i] = fieldPair.second;
 				sortedFields[i] = fieldPair.second;
 				i++;
 				i++;
 			}
 			}
+		}
 
 
-			std::sort(sortedFields.begin(), sortedFields.end(), 
-				[&](const ManagedSerializableFieldInfoPtr& x, const ManagedSerializableFieldInfoPtr& y) 
-			{
-				return x->mFieldId < y->mFieldId;
-			});
+		std::sort(sortedFields.begin(), sortedFields.end(),
+			[&](const ManagedSerializableFieldInfoPtr& x, const ManagedSerializableFieldInfoPtr& y)
+		{
+			return x->mFieldId < y->mFieldId;
+		});
 
 
-			i = 0;
-			for (auto& field : sortedFields)
-			{
-				ScriptSerializableField* serializableField = ScriptSerializableField::create(instance, field);
-				MonoObject* fieldManagedInstance = serializableField->getManagedInstance();
+		::MonoClass* serializableFieldClass = ScriptSerializableField::getMetaData()->scriptClass->_getInternalClass();
+		MonoArray* serializableFieldArray = mono_array_new(MonoManager::instance().getDomain(),
+			serializableFieldClass, (UINT32)sortedFields.size());
 
 
-				void* elemAddr = mono_array_addr_with_size(serializableFieldArray, sizeof(MonoObject*), i);
-				memcpy(elemAddr, &fieldManagedInstance, sizeof(MonoObject*));
+		UINT32 i = 0;
+		for (auto& field : sortedFields)
+		{
+			ScriptSerializableField* serializableField = ScriptSerializableField::create(instance, field);
+			MonoObject* fieldManagedInstance = serializableField->getManagedInstance();
 
 
-				i++;
-			}
+			void* elemAddr = mono_array_addr_with_size(serializableFieldArray, sizeof(MonoObject*), i);
+			memcpy(elemAddr, &fieldManagedInstance, sizeof(MonoObject*));
 
 
-			FieldsField->setValue(instance, serializableFieldArray);
+			i++;
 		}
 		}
 
 
+		FieldsField->setValue(instance, serializableFieldArray);
+
 		return nativeInstance;
 		return nativeInstance;
 	}
 	}
 }
 }