Просмотр исходного кода

Renderable inspector (not tested)

BearishSun 10 лет назад
Родитель
Сommit
4511ec8735

+ 13 - 0
BansheeEngine/Include/BsRenderable.h

@@ -62,6 +62,19 @@ namespace BansheeEngine
 		 */
 		void setMaterial(const MaterialType& material);
 
+		/**
+		 * @brief	Returns all materials used for rendering this renderable. Each of the materials is used for rendering
+		 * 			a single sub-mesh.
+		 */
+		const Vector<MaterialType>& getMaterials() { return mMaterials; }
+
+		/**
+		 * @brief	Sets all materials used for rendering this renderable. Each of the materials is used for rendering
+		 * 			a single sub-mesh. If number of materials is larger than number of sub-meshes, they will be ignored.
+		 * 			If lower, the remaining materials will be removed.
+		 */
+		void setMaterials(const Vector<MaterialType>& materials);
+
 		/**
 		 * @brief	Sets the layer bitfield that controls whether a renderable is considered 
 		 *			visible in a specific camera. Renderable layer must match camera layer

+ 16 - 0
BansheeEngine/Source/BsRenderable.cpp

@@ -52,6 +52,22 @@ namespace BansheeEngine
 		_markCoreDirty();
 	}
 
+	template<bool Core>
+	void TRenderable<Core>::setMaterials(const Vector<MaterialType>& materials)
+	{
+		UINT32 numMaterials = (UINT32)mMaterials.size();
+		UINT32 min = std::min(numMaterials, (UINT32)materials.size());
+
+		for (UINT32 i = 0; i < min; i++)
+			mMaterials[i] = materials[i];
+
+		for (UINT32 i = min; i < numMaterials; i++)
+			mMaterials[i] = nullptr;
+
+		_markResourcesDirty();
+		_markCoreDirty();
+	}
+
 	template<bool Core>
 	void TRenderable<Core>::setMaterial(const MaterialType& material)
 	{

+ 178 - 0
MBansheeEditor/Inspectors/RenderableInspector.cs

@@ -0,0 +1,178 @@
+using System.Collections.Generic;
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /// <summary>
+    /// Renders an inspector for the <see cref="Renderable"/> component.
+    /// </summary>
+    [CustomInspector(typeof(Renderable))]
+    internal class RenderableInspector : Inspector
+    {
+        private GUIResourceField meshField;
+        private GUIListBoxField layersField;
+        private GUIArray materialsField;
+        private List<MaterialParamGUI[]> materialParams = new List<MaterialParamGUI[]>();
+        private bool isInitialized;
+
+        private ulong layersValue = 0;
+        private Material[] materials;
+
+        /// <summary>
+        /// Recreates all the GUI elements used by this inspector.
+        /// </summary>
+        private void RebuildGUI()
+        {
+            layout.Clear();
+
+            Renderable renderable = referencedObject as Renderable;
+            if (renderable == null)
+                return;
+
+            meshField = new GUIResourceField(typeof(Mesh), new LocEdString("Mesh"));
+            layersField = new GUIListBoxField(Layers.Names, true, new LocEdString("Layers"));
+
+            layout.AddElement(meshField);
+            layout.AddElement(layersField);
+
+            materials = renderable.Materials;
+            materialsField = GUIArray.Create<MaterialArrayRow>(new LocEdString("Materials"), materials, layout);
+
+            meshField.OnChanged += x => renderable.Mesh = x as Mesh;
+            layersField.OnSelectionChanged += x =>
+            {
+                ulong layers = 0;
+                bool[] states = layersField.States;
+                for (int i = 0; i < states.Length; i++)
+                    layers |= states[i] ? Layers.Values[i] : 0;
+
+                layersValue = layers;
+                renderable.Layers = layers;
+            };
+
+            materialParams.Clear();
+            if (materials != null)
+            {
+                for (int i = 0; i < materials.Length; i++)
+                {
+                    if (materials[i] == null)
+                        continue;
+
+                    layout.AddSpace(10);
+
+                    MaterialParamGUI[] matParams = MaterialInspector.CreateMaterialGUI(materials[i], layout);
+                    materialParams.Add(matParams);
+                }
+            }
+        }
+
+        /// <inheritdoc/>
+        internal override bool Refresh()
+        {
+            Renderable renderable = referencedObject as Renderable;
+            if (renderable == null)
+                return false;
+
+            if (!isInitialized)
+            {
+                RebuildGUI();
+
+                isInitialized = true;
+            }
+
+            bool rebuildGUI = false;
+
+            Material[] newMaterials = renderable.Materials;
+            if (newMaterials == null)
+                rebuildGUI = materials != null;
+            else
+            {
+                if (materials == null)
+                    rebuildGUI = true;
+                else
+                {
+                    if (materials.Length != newMaterials.Length)
+                        rebuildGUI = true;
+                    else
+                    {
+                        for (int i = 0; i < materials.Length; i++)
+                        {
+                            if (materials[i] != newMaterials[i])
+                            {
+                                rebuildGUI = true;
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (rebuildGUI)
+                RebuildGUI();
+
+            bool anythingModified = materialsField.Refresh();
+
+            if (meshField.Value != renderable.Mesh)
+            {
+                meshField.Value = renderable.Mesh;
+                anythingModified = true;
+            }
+
+            if (layersValue != renderable.Layers)
+            {
+                bool[] states = new bool[64];
+                for (int i = 0; i < states.Length; i++)
+                    states[i] = (renderable.Layers & Layers.Values[i]) == Layers.Values[i];
+
+                layersField.States = states;
+                layersValue = renderable.Layers;
+
+                anythingModified = true;
+            }
+
+            for(int i = 0; i < materialParams.Count; i++)
+            {
+                if (materialParams[i] != null)
+                {
+                    foreach (var param in materialParams[i])
+                        anythingModified |= param.Refresh(materials[i]);
+                }
+            }
+
+            return anythingModified;
+        }
+
+        /// <summary>
+        /// Row element used for displaying GUI for material array elements.
+        /// </summary>
+        public class MaterialArrayRow : GUIListRow
+        {
+            private GUIResourceField materialField;
+
+            /// <inheritdoc/>
+            protected override GUILayoutX CreateGUI(GUILayoutY layout)
+            {
+                GUILayoutX titleLayout = layout.AddLayoutX();
+                materialField = new GUIResourceField(typeof(Material), new LocEdString(seqIndex + ". "));
+                titleLayout.AddElement(materialField);
+
+                materialField.OnChanged += SetValue;
+
+                return titleLayout;
+            }
+
+            /// <inheritdoc/>
+            internal protected override bool Refresh()
+            {
+                Material newValue = GetValue<Material>();
+                if (materialField.Value != newValue)
+                {
+                    materialField.Value = newValue;
+                    return true;
+                }
+
+                return false;
+            }
+        }
+    }
+}

+ 1 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -62,6 +62,7 @@
     <Compile Include="Inspectors\MeshInspector.cs" />
     <Compile Include="Inspectors\PlainTextInspector.cs" />
     <Compile Include="Inspectors\PrefabInspector.cs" />
+    <Compile Include="Inspectors\RenderableInspector.cs" />
     <Compile Include="Inspectors\ScriptCodeInspector.cs" />
     <Compile Include="Inspectors\SpriteTextureInspector.cs" />
     <Compile Include="Inspectors\Texture2DInspector.cs" />

+ 21 - 0
MBansheeEngine/NativeRenderable.cs

@@ -65,6 +65,24 @@ namespace BansheeEngine
             Internal_Create(this, sceneObjPtr);
         }
 
+        internal Material[] Materials
+        {
+            get { return materials; }
+            set
+            {
+                int newNumMaterials = value != null ? value.Length : 0;
+                int min = MathEx.Min(materials.Length, newNumMaterials);
+
+                for (int i = 0; i < min; i++)
+                    materials[i] = value[i];
+
+                for (int i = min; i < materials.Length; i++)
+                    materials[i] = null;
+
+                Internal_SetMaterials(mCachedPtr, materials);
+            }
+        }
+
         internal Material GetMaterial(int index = 0)
         {
             return materials[index];
@@ -112,6 +130,9 @@ namespace BansheeEngine
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetMaterial(IntPtr thisPtr, IntPtr material, int index);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMaterials(IntPtr thisPtr, Material[] materials);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_OnDestroy(IntPtr thisPtr);
     }

+ 9 - 0
MBansheeEngine/Renderable.cs

@@ -54,6 +54,15 @@ namespace BansheeEngine
             { _native.SetMaterial(value); serializableData.materials[0] = value; }
         }
 
+        /// <summary>
+        /// Materials to use when rendering the mesh. 
+        /// </summary>
+        public Material[] Materials
+        {
+            get { return _native.Materials; }
+            set { _native.Materials = value; }
+        }
+
         /// <summary>
         /// Returns a material for a specific sub-mesh.
         /// </summary>

+ 1 - 0
SBansheeEngine/Include/BsScriptRenderable.h

@@ -46,6 +46,7 @@ namespace BansheeEngine
 		static UINT64 internal_GetLayers(ScriptRenderable* thisPtr);
 		static void internal_SetLayers(ScriptRenderable* thisPtr, UINT64 layers);
 		static void internal_SetMaterial(ScriptRenderable* thisPtr, ScriptMaterial* material, int index);
+		static void internal_SetMaterials(ScriptRenderable* thisPtr, MonoArray* materials);
 		static void internal_OnDestroy(ScriptRenderable* thisPtr);
 	};
 }

+ 18 - 0
SBansheeEngine/Source/BsScriptRenderable.cpp

@@ -33,6 +33,7 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetLayers", &ScriptRenderable::internal_GetLayers);
 		metaData.scriptClass->addInternalCall("Internal_SetLayers", &ScriptRenderable::internal_SetLayers);
 		metaData.scriptClass->addInternalCall("Internal_SetMaterial", &ScriptRenderable::internal_SetMaterial);
+		metaData.scriptClass->addInternalCall("Internal_SetMaterials", &ScriptRenderable::internal_SetMaterials);
 		metaData.scriptClass->addInternalCall("Internal_OnDestroy", &ScriptRenderable::internal_OnDestroy);
 	}
 
@@ -98,6 +99,23 @@ namespace BansheeEngine
 		thisPtr->getInternal()->setLayer(layers);
 	}
 
+	void ScriptRenderable::internal_SetMaterials(ScriptRenderable* thisPtr, MonoArray* materials)
+	{
+		ScriptArray scriptMaterials(materials);
+
+		Vector<HMaterial> nativeMaterials(scriptMaterials.size());
+		for (UINT32 i = 0; i < scriptMaterials.size(); i++)
+		{
+			MonoObject* monoMaterial = scriptMaterials.get<MonoObject*>(i);
+			ScriptMaterial* scriptMaterial = ScriptMaterial::toNative(monoMaterial);
+
+			if (scriptMaterial != nullptr)
+				nativeMaterials[i] = scriptMaterial->getMaterialHandle();
+		}
+		
+		thisPtr->getInternal()->setMaterials(nativeMaterials);
+	}
+
 	void ScriptRenderable::internal_SetMaterial(ScriptRenderable* thisPtr, ScriptMaterial* material, int index)
 	{
 		HMaterial nativeMaterial;