MaterialInspector.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. using System.Collections.Generic;
  2. using BansheeEngine;
  3. namespace BansheeEditor
  4. {
  5. /// <summary>
  6. /// Renders an inspector for the <see cref="Material"/> resource.
  7. /// </summary>
  8. [CustomInspector(typeof (Material))]
  9. internal class MaterialInspector : Inspector
  10. {
  11. private MaterialParamGUI[] guiParams;
  12. private GUIResourceField shaderField;
  13. /// <inheritdoc/>
  14. protected internal override void Initialize()
  15. {
  16. Material material = InspectedObject as Material;
  17. if (material == null)
  18. return;
  19. shaderField = new GUIResourceField(typeof(Shader), new LocEdString("Shader"));
  20. shaderField.OnChanged += (x) =>
  21. {
  22. material.Shader = x as Shader;
  23. RebuildParamGUI(material);
  24. };
  25. Layout.AddElement(shaderField);
  26. RebuildParamGUI(material);
  27. }
  28. /// <inheritdoc/>
  29. protected internal override void Refresh()
  30. {
  31. Material material = InspectedObject as Material;
  32. if (material == null)
  33. return;
  34. if (material.Shader != shaderField.Value)
  35. {
  36. shaderField.Value = material.Shader;
  37. RebuildParamGUI(material);
  38. }
  39. if (guiParams != null)
  40. {
  41. foreach (var param in guiParams)
  42. param.Refresh(material);
  43. }
  44. }
  45. /// <summary>
  46. /// Recreates GUI elements for all material parameters.
  47. /// </summary>
  48. /// <param name="material">Material to create parameters for</param>
  49. private void RebuildParamGUI(Material material)
  50. {
  51. if (guiParams != null)
  52. {
  53. foreach (var param in guiParams)
  54. param.Destroy();
  55. guiParams = null;
  56. }
  57. if (material != null && material.Shader != null)
  58. guiParams = CreateMaterialGUI(material, Layout);
  59. }
  60. /// <summary>
  61. /// Creates a set of objects in which each object represents a GUI for a material parameter.
  62. /// </summary>
  63. /// <param name="mat">Material for whose parameters to create GUI for.</param>
  64. /// <param name="layout">Layout to add the parameter GUI elements to.</param>
  65. /// <returns>A material parameter GUI object for each supported material parameter.</returns>
  66. static internal MaterialParamGUI[] CreateMaterialGUI(Material mat, GUILayout layout)
  67. {
  68. Shader shader = mat.Shader;
  69. if (shader == null)
  70. return new MaterialParamGUI[0];
  71. List<MaterialParamGUI> guiParams = new List<MaterialParamGUI>();
  72. ShaderParameter[] shaderParams = shader.Parameters;
  73. foreach (var param in shaderParams)
  74. {
  75. switch (param.type)
  76. {
  77. case ShaderParameterType.Float:
  78. guiParams.Add(new MaterialParamFloatGUI(param, mat, layout));
  79. break;
  80. case ShaderParameterType.Vector2:
  81. guiParams.Add(new MaterialParamVec2GUI(param, mat, layout));
  82. break;
  83. case ShaderParameterType.Vector3:
  84. guiParams.Add(new MaterialParamVec3GUI(param, mat, layout));
  85. break;
  86. case ShaderParameterType.Vector4:
  87. guiParams.Add(new MaterialParamVec4GUI(param, mat, layout));
  88. break;
  89. case ShaderParameterType.Matrix3:
  90. guiParams.Add(new MaterialParamMat3GUI(param, mat, layout));
  91. break;
  92. case ShaderParameterType.Matrix4:
  93. guiParams.Add(new MaterialParamMat4GUI(param, mat, layout));
  94. break;
  95. case ShaderParameterType.Color:
  96. guiParams.Add(new MaterialParamColorGUI(param, mat, layout));
  97. break;
  98. case ShaderParameterType.Texture2D:
  99. case ShaderParameterType.Texture3D:
  100. case ShaderParameterType.TextureCube:
  101. guiParams.Add(new MaterialParamTextureGUI(param, mat, layout));
  102. break;
  103. }
  104. }
  105. return guiParams.ToArray();
  106. }
  107. }
  108. /// <summary>
  109. /// Contains GUI element(s) for a single parameter in a <see cref="Material"/>.
  110. /// </summary>
  111. internal abstract class MaterialParamGUI
  112. {
  113. protected ShaderParameter shaderParam;
  114. /// <summary>
  115. /// Creates a new material parameter GUI.
  116. /// </summary>
  117. /// <param name="shaderParam">Shader parameter to create the GUI for.</param>
  118. protected MaterialParamGUI(ShaderParameter shaderParam)
  119. {
  120. this.shaderParam = shaderParam;
  121. }
  122. /// <summary>
  123. /// Checks if the data stored in GUI and in the material matches, and updates the GUI if it doesn't.
  124. /// </summary>
  125. /// <param name="material">Material whose data to check.</param>
  126. internal abstract void Refresh(Material material);
  127. /// <summary>
  128. /// Destroys the internal GUI elements.
  129. /// </summary>
  130. internal abstract void Destroy();
  131. }
  132. /// <summary>
  133. /// Contains GUI element(s) for a single floating point parameter in a <see cref="Material"/>.
  134. /// </summary>
  135. internal class MaterialParamFloatGUI : MaterialParamGUI
  136. {
  137. private GUIFloatField guiElem;
  138. /// <summary>
  139. /// Creates a new material parameter GUI.
  140. /// </summary>
  141. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of floating point type.</param>
  142. /// <param name="material">Material the parameter is a part of.</param>
  143. /// <param name="layout">Layout to append the GUI elements to.</param>
  144. internal MaterialParamFloatGUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  145. : base(shaderParam)
  146. {
  147. LocString title = new LocEdString(shaderParam.name);
  148. guiElem = new GUIFloatField(title);
  149. guiElem.OnChanged += (x) =>
  150. {
  151. material.SetFloat(shaderParam.name, x);
  152. EditorApplication.SetDirty(material);
  153. };
  154. layout.AddElement(guiElem);
  155. }
  156. /// <inheritdoc/>
  157. internal override void Refresh(Material material)
  158. {
  159. guiElem.Value = material.GetFloat(shaderParam.name);
  160. }
  161. /// <inheritdoc/>
  162. internal override void Destroy()
  163. {
  164. guiElem.Destroy();
  165. }
  166. }
  167. /// <summary>
  168. /// Contains GUI element(s) for a single 2D vector parameter in a <see cref="Material"/>.
  169. /// </summary>
  170. internal class MaterialParamVec2GUI : MaterialParamGUI
  171. {
  172. private GUIVector2Field guiElem;
  173. /// <summary>
  174. /// Creates a new material parameter GUI.
  175. /// </summary>
  176. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 2D vector type.</param>
  177. /// <param name="material">Material the parameter is a part of.</param>
  178. /// <param name="layout">Layout to append the GUI elements to.</param>
  179. internal MaterialParamVec2GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  180. : base(shaderParam)
  181. {
  182. LocString title = new LocEdString(shaderParam.name);
  183. guiElem = new GUIVector2Field(title);
  184. guiElem.OnChanged += (x) =>
  185. {
  186. material.SetVector2(shaderParam.name, x);
  187. EditorApplication.SetDirty(material);
  188. };
  189. layout.AddElement(guiElem);
  190. }
  191. /// <inheritdoc/>
  192. internal override void Refresh(Material material)
  193. {
  194. guiElem.Value = material.GetVector2(shaderParam.name);
  195. }
  196. /// <inheritdoc/>
  197. internal override void Destroy()
  198. {
  199. guiElem.Destroy();
  200. }
  201. }
  202. /// <summary>
  203. /// Contains GUI element(s) for a single 3D vector parameter in a <see cref="Material"/>.
  204. /// </summary>
  205. internal class MaterialParamVec3GUI : MaterialParamGUI
  206. {
  207. private GUIVector3Field guiElem;
  208. /// <summary>
  209. /// Creates a new material parameter GUI.
  210. /// </summary>
  211. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 3D vector type.</param>
  212. /// <param name="material">Material the parameter is a part of.</param>
  213. /// <param name="layout">Layout to append the GUI elements to.</param>
  214. internal MaterialParamVec3GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  215. : base(shaderParam)
  216. {
  217. LocString title = new LocEdString(shaderParam.name);
  218. guiElem = new GUIVector3Field(title);
  219. guiElem.OnChanged += (x) =>
  220. {
  221. material.SetVector3(shaderParam.name, x);
  222. EditorApplication.SetDirty(material);
  223. };
  224. layout.AddElement(guiElem);
  225. }
  226. /// <inheritdoc/>
  227. internal override void Refresh(Material material)
  228. {
  229. guiElem.Value = material.GetVector3(shaderParam.name);
  230. }
  231. /// <inheritdoc/>
  232. internal override void Destroy()
  233. {
  234. guiElem.Destroy();
  235. }
  236. }
  237. /// <summary>
  238. /// Contains GUI element(s) for a single 4D vector parameter in a <see cref="Material"/>.
  239. /// </summary>
  240. internal class MaterialParamVec4GUI : MaterialParamGUI
  241. {
  242. private GUIVector4Field guiElem;
  243. /// <summary>
  244. /// Creates a new material parameter GUI.
  245. /// </summary>
  246. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 4D vector type.</param>
  247. /// <param name="material">Material the parameter is a part of.</param>
  248. /// <param name="layout">Layout to append the GUI elements to.</param>
  249. internal MaterialParamVec4GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  250. : base(shaderParam)
  251. {
  252. LocString title = new LocEdString(shaderParam.name);
  253. guiElem = new GUIVector4Field(title);
  254. guiElem.OnChanged += (x) =>
  255. {
  256. material.SetVector4(shaderParam.name, x);
  257. EditorApplication.SetDirty(material);
  258. };
  259. layout.AddElement(guiElem);
  260. }
  261. /// <inheritdoc/>
  262. internal override void Refresh(Material material)
  263. {
  264. guiElem.Value = material.GetVector4(shaderParam.name);
  265. }
  266. /// <inheritdoc/>
  267. internal override void Destroy()
  268. {
  269. guiElem.Destroy();
  270. }
  271. }
  272. /// <summary>
  273. /// Contains GUI element(s) for a single 3x3 matrix parameter in a <see cref="Material"/>.
  274. /// </summary>
  275. internal class MaterialParamMat3GUI : MaterialParamGUI
  276. {
  277. private const int MAT_SIZE = 3;
  278. private GUIFloatField[] guiMatFields = new GUIFloatField[MAT_SIZE * MAT_SIZE];
  279. /// <summary>
  280. /// Creates a new material parameter GUI.
  281. /// </summary>
  282. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 3x3 matrix type.</param>
  283. /// <param name="material">Material the parameter is a part of.</param>
  284. /// <param name="layout">Layout to append the GUI elements to.</param>
  285. internal MaterialParamMat3GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  286. : base(shaderParam)
  287. {
  288. LocString title = new LocEdString(shaderParam.name);
  289. GUILabel guiTitle = new GUILabel(title, GUIOption.FixedWidth(100));
  290. GUILayout mainLayout = layout.AddLayoutX();
  291. mainLayout.AddElement(guiTitle);
  292. GUILayoutY contentLayout = mainLayout.AddLayoutY();
  293. GUILayoutX[] rows = new GUILayoutX[MAT_SIZE];
  294. for (int i = 0; i < MAT_SIZE; i++)
  295. rows[i] = contentLayout.AddLayoutX();
  296. for (int row = 0; row < MAT_SIZE; row++)
  297. {
  298. for (int col = 0; col < MAT_SIZE; col++)
  299. {
  300. int index = row * MAT_SIZE + col;
  301. guiMatFields[index] = new GUIFloatField(row + ", " + col, 30);
  302. GUIFloatField field = guiMatFields[index];
  303. rows[row].AddElement(field);
  304. int hoistedRow = row;
  305. int hoistedCol = col;
  306. field.OnChanged += (x) =>
  307. {
  308. Matrix3 value = material.GetMatrix3(shaderParam.name);
  309. value[hoistedRow, hoistedCol] = x;
  310. material.SetMatrix3(shaderParam.name, value);
  311. EditorApplication.SetDirty(material);
  312. };
  313. }
  314. }
  315. }
  316. /// <inheritdoc/>
  317. internal override void Refresh(Material material)
  318. {
  319. Matrix3 value = material.GetMatrix3(shaderParam.name);
  320. for (int row = 0; row < MAT_SIZE; row++)
  321. {
  322. for (int col = 0; col < MAT_SIZE; col++)
  323. {
  324. int index = row * MAT_SIZE + col;
  325. guiMatFields[index].Value = value[row, col];
  326. }
  327. }
  328. }
  329. /// <inheritdoc/>
  330. internal override void Destroy()
  331. {
  332. for (int row = 0; row < MAT_SIZE; row++)
  333. {
  334. for (int col = 0; col < MAT_SIZE; col++)
  335. {
  336. int index = row*MAT_SIZE + col;
  337. guiMatFields[index].Destroy();
  338. }
  339. }
  340. }
  341. }
  342. /// <summary>
  343. /// Contains GUI element(s) for a single 4x4 matrix parameter in a <see cref="Material"/>.
  344. /// </summary>
  345. internal class MaterialParamMat4GUI : MaterialParamGUI
  346. {
  347. private const int MAT_SIZE = 4;
  348. private GUIFloatField[] guiMatFields = new GUIFloatField[MAT_SIZE * MAT_SIZE];
  349. /// <summary>
  350. /// Creates a new material parameter GUI.
  351. /// </summary>
  352. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of 4x4 matrix type.</param>
  353. /// <param name="material">Material the parameter is a part of.</param>
  354. /// <param name="layout">Layout to append the GUI elements to.</param>
  355. internal MaterialParamMat4GUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  356. : base(shaderParam)
  357. {
  358. LocString title = new LocEdString(shaderParam.name);
  359. GUILabel guiTitle = new GUILabel(title, GUIOption.FixedWidth(100));
  360. GUILayout mainLayout = layout.AddLayoutX();
  361. mainLayout.AddElement(guiTitle);
  362. GUILayoutY contentLayout = mainLayout.AddLayoutY();
  363. GUILayoutX[] rows = new GUILayoutX[MAT_SIZE];
  364. for (int i = 0; i < MAT_SIZE; i++)
  365. rows[i] = contentLayout.AddLayoutX();
  366. for (int row = 0; row < MAT_SIZE; row++)
  367. {
  368. for (int col = 0; col < MAT_SIZE; col++)
  369. {
  370. int index = row * MAT_SIZE + col;
  371. guiMatFields[index] = new GUIFloatField(row + ", " + col, 30);
  372. GUIFloatField field = guiMatFields[index];
  373. rows[row].AddElement(field);
  374. int hoistedRow = row;
  375. int hoistedCol = col;
  376. field.OnChanged += (x) =>
  377. {
  378. Matrix4 value = material.GetMatrix4(shaderParam.name);
  379. value[hoistedRow, hoistedCol] = x;
  380. material.SetMatrix4(shaderParam.name, value);
  381. EditorApplication.SetDirty(material);
  382. };
  383. }
  384. }
  385. }
  386. /// <inheritdoc/>
  387. internal override void Refresh(Material material)
  388. {
  389. Matrix4 value = material.GetMatrix4(shaderParam.name);
  390. for (int row = 0; row < MAT_SIZE; row++)
  391. {
  392. for (int col = 0; col < MAT_SIZE; col++)
  393. {
  394. int index = row * MAT_SIZE + col;
  395. guiMatFields[index].Value = value[row, col];
  396. }
  397. }
  398. }
  399. /// <inheritdoc/>
  400. internal override void Destroy()
  401. {
  402. for (int row = 0; row < MAT_SIZE; row++)
  403. {
  404. for (int col = 0; col < MAT_SIZE; col++)
  405. {
  406. int index = row * MAT_SIZE + col;
  407. guiMatFields[index].Destroy();
  408. }
  409. }
  410. }
  411. }
  412. /// <summary>
  413. /// Contains GUI element(s) for a single color parameter in a <see cref="Material"/>.
  414. /// </summary>
  415. internal class MaterialParamColorGUI : MaterialParamGUI
  416. {
  417. private GUIColorField guiElem;
  418. /// <summary>
  419. /// Creates a new material parameter GUI.
  420. /// </summary>
  421. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of color type.</param>
  422. /// <param name="material">Material the parameter is a part of.</param>
  423. /// <param name="layout">Layout to append the GUI elements to.</param>
  424. internal MaterialParamColorGUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  425. : base(shaderParam)
  426. {
  427. LocString title = new LocEdString(shaderParam.name);
  428. guiElem = new GUIColorField(title);
  429. guiElem.OnChanged += (x) =>
  430. {
  431. material.SetColor(shaderParam.name, x);
  432. EditorApplication.SetDirty(material);
  433. };
  434. layout.AddElement(guiElem);
  435. }
  436. /// <inheritdoc/>
  437. internal override void Refresh(Material material)
  438. {
  439. guiElem.Value = material.GetColor(shaderParam.name);
  440. }
  441. /// <inheritdoc/>
  442. internal override void Destroy()
  443. {
  444. guiElem.Destroy();
  445. }
  446. }
  447. /// <summary>
  448. /// Contains GUI element(s) for a single texture parameter in a <see cref="Material"/>.
  449. /// </summary>
  450. internal class MaterialParamTextureGUI : MaterialParamGUI
  451. {
  452. private GUITextureField guiElem;
  453. /// <summary>
  454. /// Creates a new material parameter GUI.
  455. /// </summary>
  456. /// <param name="shaderParam">Shader parameter to create the GUI for. Must be of texture type.</param>
  457. /// <param name="material">Material the parameter is a part of.</param>
  458. /// <param name="layout">Layout to append the GUI elements to.</param>
  459. internal MaterialParamTextureGUI(ShaderParameter shaderParam, Material material, GUILayout layout)
  460. : base(shaderParam)
  461. {
  462. LocString title = new LocEdString(shaderParam.name);
  463. guiElem = new GUITextureField(title);
  464. switch (shaderParam.type)
  465. {
  466. case ShaderParameterType.Texture2D:
  467. guiElem.OnChanged += (x) =>
  468. {
  469. material.SetTexture2D(shaderParam.name, x as Texture2D);
  470. EditorApplication.SetDirty(material);
  471. };
  472. break;
  473. case ShaderParameterType.Texture3D:
  474. guiElem.OnChanged += (x) =>
  475. {
  476. material.SetTexture3D(shaderParam.name, x as Texture3D);
  477. EditorApplication.SetDirty(material);
  478. };
  479. break;
  480. case ShaderParameterType.TextureCube:
  481. guiElem.OnChanged += (x) =>
  482. {
  483. material.SetTextureCube(shaderParam.name, x as TextureCube);
  484. EditorApplication.SetDirty(material);
  485. };
  486. break;
  487. }
  488. layout.AddElement(guiElem);
  489. }
  490. /// <inheritdoc/>
  491. internal override void Refresh(Material material)
  492. {
  493. Texture value = null;
  494. switch (shaderParam.type)
  495. {
  496. case ShaderParameterType.Texture2D:
  497. value = material.GetTexture2D(shaderParam.name);
  498. break;
  499. case ShaderParameterType.Texture3D:
  500. value = material.GetTexture3D(shaderParam.name);
  501. break;
  502. case ShaderParameterType.TextureCube:
  503. value = material.GetTextureCube(shaderParam.name);
  504. break;
  505. }
  506. guiElem.Value = value;
  507. }
  508. /// <inheritdoc/>
  509. internal override void Destroy()
  510. {
  511. guiElem.Destroy();
  512. }
  513. }
  514. }