using System.Collections.Generic; using BansheeEngine; namespace BansheeEditor { /// /// Renders an inspector for the resource. /// [CustomInspector(typeof (Material))] internal class MaterialInspector : Inspector { private MaterialParamGUI[] guiParams; private GUIResourceField shaderField; /// protected internal override void Initialize() { Material material = InspectedObject as Material; if (material == null) return; shaderField = new GUIResourceField(typeof(Shader), new LocEdString("Shader")); shaderField.OnChanged += (x) => { material.Shader = x as Shader; RebuildParamGUI(material); }; Layout.AddElement(shaderField); RebuildParamGUI(material); } /// protected internal override void Refresh() { Material material = InspectedObject as Material; if (material == null) return; if (material.Shader != shaderField.Value) { shaderField.Value = material.Shader; RebuildParamGUI(material); } if (guiParams != null) { foreach (var param in guiParams) param.Refresh(material); } } /// /// Recreates GUI elements for all material parameters. /// /// Material to create parameters for 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); } /// /// Creates a set of objects in which each object represents a GUI for a material parameter. /// /// Material for whose parameters to create GUI for. /// Layout to add the parameter GUI elements to. /// A material parameter GUI object for each supported material parameter. static internal MaterialParamGUI[] CreateMaterialGUI(Material mat, GUILayout layout) { Shader shader = mat.Shader; if (shader == null) return new MaterialParamGUI[0]; List guiParams = new List(); 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(); } } /// /// Contains GUI element(s) for a single parameter in a . /// internal abstract class MaterialParamGUI { protected ShaderParameter shaderParam; /// /// Creates a new material parameter GUI. /// /// Shader parameter to create the GUI for. protected MaterialParamGUI(ShaderParameter shaderParam) { this.shaderParam = shaderParam; } /// /// Checks if the data stored in GUI and in the material matches, and updates the GUI if it doesn't. /// /// Material whose data to check. internal abstract void Refresh(Material material); /// /// Destroys the internal GUI elements. /// internal abstract void Destroy(); } /// /// Contains GUI element(s) for a single floating point parameter in a . /// internal class MaterialParamFloatGUI : MaterialParamGUI { private GUIFloatField guiElem; /// /// Creates a new material parameter GUI. /// /// Shader parameter to create the GUI for. Must be of floating point type. /// Material the parameter is a part of. /// Layout to append the GUI elements to. 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); EditorApplication.SetDirty(material); }; layout.AddElement(guiElem); } /// internal override void Refresh(Material material) { guiElem.Value = material.GetFloat(shaderParam.name); } /// internal override void Destroy() { guiElem.Destroy(); } } /// /// Contains GUI element(s) for a single 2D vector parameter in a . /// internal class MaterialParamVec2GUI : MaterialParamGUI { private GUIVector2Field guiElem; /// /// Creates a new material parameter GUI. /// /// Shader parameter to create the GUI for. Must be of 2D vector type. /// Material the parameter is a part of. /// Layout to append the GUI elements to. 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); EditorApplication.SetDirty(material); }; layout.AddElement(guiElem); } /// internal override void Refresh(Material material) { guiElem.Value = material.GetVector2(shaderParam.name); } /// internal override void Destroy() { guiElem.Destroy(); } } /// /// Contains GUI element(s) for a single 3D vector parameter in a . /// internal class MaterialParamVec3GUI : MaterialParamGUI { private GUIVector3Field guiElem; /// /// Creates a new material parameter GUI. /// /// Shader parameter to create the GUI for. Must be of 3D vector type. /// Material the parameter is a part of. /// Layout to append the GUI elements to. 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); EditorApplication.SetDirty(material); }; layout.AddElement(guiElem); } /// internal override void Refresh(Material material) { guiElem.Value = material.GetVector3(shaderParam.name); } /// internal override void Destroy() { guiElem.Destroy(); } } /// /// Contains GUI element(s) for a single 4D vector parameter in a . /// internal class MaterialParamVec4GUI : MaterialParamGUI { private GUIVector4Field guiElem; /// /// Creates a new material parameter GUI. /// /// Shader parameter to create the GUI for. Must be of 4D vector type. /// Material the parameter is a part of. /// Layout to append the GUI elements to. 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); EditorApplication.SetDirty(material); }; layout.AddElement(guiElem); } /// internal override void Refresh(Material material) { guiElem.Value = material.GetVector4(shaderParam.name); } /// internal override void Destroy() { guiElem.Destroy(); } } /// /// Contains GUI element(s) for a single 3x3 matrix parameter in a . /// internal class MaterialParamMat3GUI : MaterialParamGUI { private const int MAT_SIZE = 3; private GUIFloatField[] guiMatFields = new GUIFloatField[MAT_SIZE * MAT_SIZE]; /// /// Creates a new material parameter GUI. /// /// Shader parameter to create the GUI for. Must be of 3x3 matrix type. /// Material the parameter is a part of. /// Layout to append the GUI elements to. 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); EditorApplication.SetDirty(material); }; } } } /// internal override void Refresh(Material material) { Matrix3 value = material.GetMatrix3(shaderParam.name); for (int row = 0; row < MAT_SIZE; row++) { for (int col = 0; col < MAT_SIZE; col++) { int index = row * MAT_SIZE + col; guiMatFields[index].Value = value[row, col]; } } } /// 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(); } } } } /// /// Contains GUI element(s) for a single 4x4 matrix parameter in a . /// internal class MaterialParamMat4GUI : MaterialParamGUI { private const int MAT_SIZE = 4; private GUIFloatField[] guiMatFields = new GUIFloatField[MAT_SIZE * MAT_SIZE]; /// /// Creates a new material parameter GUI. /// /// Shader parameter to create the GUI for. Must be of 4x4 matrix type. /// Material the parameter is a part of. /// Layout to append the GUI elements to. 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); EditorApplication.SetDirty(material); }; } } } /// internal override void Refresh(Material material) { Matrix4 value = material.GetMatrix4(shaderParam.name); for (int row = 0; row < MAT_SIZE; row++) { for (int col = 0; col < MAT_SIZE; col++) { int index = row * MAT_SIZE + col; guiMatFields[index].Value = value[row, col]; } } } /// 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(); } } } } /// /// Contains GUI element(s) for a single color parameter in a . /// internal class MaterialParamColorGUI : MaterialParamGUI { private GUIColorField guiElem; /// /// Creates a new material parameter GUI. /// /// Shader parameter to create the GUI for. Must be of color type. /// Material the parameter is a part of. /// Layout to append the GUI elements to. 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); EditorApplication.SetDirty(material); }; layout.AddElement(guiElem); } /// internal override void Refresh(Material material) { guiElem.Value = material.GetColor(shaderParam.name); } /// internal override void Destroy() { guiElem.Destroy(); } } /// /// Contains GUI element(s) for a single texture parameter in a . /// internal class MaterialParamTextureGUI : MaterialParamGUI { private GUITextureField guiElem; /// /// Creates a new material parameter GUI. /// /// Shader parameter to create the GUI for. Must be of texture type. /// Material the parameter is a part of. /// Layout to append the GUI elements to. 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); EditorApplication.SetDirty(material); }; break; case ShaderParameterType.Texture3D: guiElem.OnChanged += (x) => { material.SetTexture3D(shaderParam.name, x as Texture3D); EditorApplication.SetDirty(material); }; break; case ShaderParameterType.TextureCube: guiElem.OnChanged += (x) => { material.SetTextureCube(shaderParam.name, x as TextureCube); EditorApplication.SetDirty(material); }; break; } layout.AddElement(guiElem); } /// internal override void 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; } guiElem.Value = value; } /// internal override void Destroy() { guiElem.Destroy(); } } }