texture_settings_dialog.vala 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * Copyright (c) 2012-2024 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: GPL-3.0-or-later
  4. */
  5. namespace Crown
  6. {
  7. public enum TextureFormat
  8. {
  9. BC1,
  10. BC2,
  11. BC3,
  12. BC4,
  13. BC5,
  14. PTC14,
  15. RGB8,
  16. RGBA8,
  17. COUNT
  18. }
  19. const string texture_formats[] =
  20. {
  21. "BC1",
  22. "BC2",
  23. "BC3",
  24. "BC4",
  25. "BC5",
  26. "PTC14",
  27. "RGB8",
  28. "RGBA8"
  29. };
  30. public class TextureSettingsDialog : Gtk.Dialog
  31. {
  32. public Project _project;
  33. public Database _database;
  34. public Database _texture_database;
  35. public Guid _texture_id;
  36. public ProjectStore _store;
  37. public PropertyGridSet _texture_set;
  38. public Gtk.ListStore _platforms_store;
  39. public Gtk.TreeView _platforms;
  40. public Gtk.Stack _stack;
  41. public bool _never_opened_before;
  42. public string _texture_path;
  43. // Input page.
  44. public ResourceChooserButton _texture_name;
  45. public EntryText _source;
  46. // Output page.
  47. public ComboBoxMap _format;
  48. public CheckBox _generate_mips;
  49. public EntryDouble _mip_skip_smallest;
  50. public CheckBox _normal_map;
  51. public Gtk.Box _box;
  52. public signal void texture_saved();
  53. private void text_func(Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter)
  54. {
  55. Value? platform;
  56. model.get_value(iter, 0, out platform);
  57. cell.set_property("text", ((TargetPlatform)platform).to_label());
  58. }
  59. public TextureSettingsDialog(Project project, ProjectStore store, Database database)
  60. {
  61. _project = project;
  62. _database = database;
  63. _texture_database = new Database(project);
  64. _texture_id = GUID_ZERO;
  65. _store = store;
  66. _platforms_store = new Gtk.ListStore(1
  67. , typeof(TargetPlatform) // platform name
  68. );
  69. for (int p = 0; p < TargetPlatform.COUNT; ++p) {
  70. Gtk.TreeIter iter;
  71. _platforms_store.insert_with_values(out iter, -1, 0, (TargetPlatform)p, -1);
  72. }
  73. Gtk.CellRendererText text_renderer = new Gtk.CellRendererText();
  74. Gtk.TreeViewColumn column = new Gtk.TreeViewColumn.with_attributes("Target Platform", text_renderer, null);
  75. column.set_cell_data_func(text_renderer, text_func);
  76. _platforms = new Gtk.TreeView.with_model(_platforms_store);
  77. _platforms.append_column(column);
  78. _platforms.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE);
  79. _platforms.get_selection().changed.connect(on_platforms_selection_changed);
  80. this.title = "Texture Settings";
  81. this.border_width = 0;
  82. this.set_icon_name(CROWN_ICON_NAME);
  83. _texture_set = new PropertyGridSet();
  84. _texture_set.border_width = 12;
  85. _texture_path = "";
  86. // Input grid.
  87. _texture_name = new ResourceChooserButton(_store, "texture");
  88. _texture_name.value_changed.connect(on_texture_resource_value_changed);
  89. _source = new EntryText();
  90. _source.sensitive = false;
  91. PropertyGrid cv;
  92. cv = new PropertyGrid();
  93. cv.column_homogeneous = true;
  94. cv.add_row("Name", _texture_name);
  95. _texture_set.add_property_grid(cv, "Texture");
  96. cv = new PropertyGrid();
  97. cv.column_homogeneous = true;
  98. cv.add_row("Source", _source);
  99. _texture_set.add_property_grid(cv, "Input");
  100. // Output grid.
  101. _format = new ComboBoxMap(TextureFormat.BC1
  102. , texture_formats
  103. , texture_formats
  104. );
  105. _format.value_changed.connect(on_format_value_changed);
  106. _generate_mips = new CheckBox();
  107. _generate_mips.value = true;
  108. _generate_mips.value_changed.connect(on_generate_mips_value_changed);
  109. _mip_skip_smallest = new EntryDouble(0, 0, 32);
  110. _mip_skip_smallest.value_changed.connect(on_mip_skip_smallest_value_changed);
  111. _normal_map = new CheckBox();
  112. _normal_map.value = false;
  113. _normal_map.value_changed.connect(on_normal_map_value_changed);
  114. cv = new PropertyGrid();
  115. cv.column_homogeneous = true;
  116. cv.add_row("Format", _format);
  117. cv.add_row("Generate Mips", _generate_mips);
  118. cv.add_row("Skip Smallest Mips", _mip_skip_smallest);
  119. cv.add_row("Normal Map", _normal_map);
  120. _texture_set.add_property_grid(cv, "Output");
  121. _stack = new Gtk.Stack();
  122. _stack.add_named(new Gtk.Label("Select one or more platforms to change its settings"), "none-selected");
  123. _stack.add_named(_texture_set, "some-selected");
  124. _box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
  125. _box.pack_start(_platforms, false, true, 0);
  126. _box.pack_start(_stack, false, true, 0);
  127. _box.vexpand = true;
  128. this.get_content_area().border_width = 0;
  129. this.get_content_area().add(_box);
  130. this.delete_event.connect(on_delete_event);
  131. _never_opened_before = true;
  132. _stack.map.connect(on_stack_map);
  133. }
  134. public void on_stack_map()
  135. {
  136. if (_never_opened_before) {
  137. _never_opened_before = false;
  138. TargetPlatform host_platform = TargetPlatform.COUNT;
  139. #if CROWN_PLATFORM_WINDOWS
  140. host_platform = TargetPlatform.WINDOWS;
  141. #elif CROWN_PLATFORM_LINUX
  142. host_platform = TargetPlatform.LINUX;
  143. #endif
  144. if (host_platform == TargetPlatform.COUNT) {
  145. _platforms.get_selection().select_path(new Gtk.TreePath.first());
  146. } else {
  147. _platforms_store.foreach((model, path, iter) => {
  148. Value platform;
  149. model.get_value(iter, 0, out platform);
  150. if (((TargetPlatform)platform) == host_platform) {
  151. _platforms.get_selection().select_iter(iter);
  152. return true;
  153. }
  154. return false;
  155. });
  156. }
  157. }
  158. _platforms.grab_focus();
  159. }
  160. public int load_texture(string texture_name)
  161. {
  162. string new_texture_path = texture_name + ".texture";
  163. if (_texture_path != new_texture_path)
  164. save();
  165. _texture_database.reset();
  166. if (_texture_database.add_from_resource_path(out _texture_id, new_texture_path) != 0) {
  167. _texture_id = GUID_ZERO;
  168. return -1;
  169. }
  170. _texture_path = new_texture_path;
  171. on_platforms_selection_changed();
  172. return 0;
  173. }
  174. public void set_texture(string texture_name)
  175. {
  176. if (load_texture(texture_name) == 0)
  177. _texture_name.value = texture_name;
  178. }
  179. public void on_texture_resource_value_changed()
  180. {
  181. load_texture(_texture_name.value);
  182. }
  183. public bool are_values_equal(Value? a, Value? b)
  184. {
  185. if (a.type() != b.type())
  186. return false;
  187. if (a.holds(typeof(bool))) {
  188. return (bool)a == (bool)b;
  189. } else if (a.holds(typeof(double))) {
  190. return (double)a == (double)b;
  191. } else if (a.holds(typeof(string))) {
  192. return (string)a == (string)b;
  193. } else if (a == null && b == null) {
  194. return true;
  195. }
  196. return false;
  197. }
  198. public void on_platforms_selection_changed()
  199. {
  200. if (_texture_id == GUID_ZERO)
  201. return;
  202. if (_platforms.get_selection().count_selected_rows() > 0) {
  203. _stack.set_visible_child_full("some-selected", Gtk.StackTransitionType.NONE);
  204. } else {
  205. _stack.set_visible_child_full("none-selected", Gtk.StackTransitionType.NONE);
  206. return;
  207. }
  208. string property_names[] = { "source", "format", "generate_mips", "mip_skip_smallest", "normal_map" };
  209. Property properties[] = { _source, _format, _generate_mips, _mip_skip_smallest, _normal_map };
  210. for (int i = 0; i < properties.length; ++i)
  211. properties[i].set_data("init", false);
  212. for (int i = 0; i < properties.length; ++i) {
  213. _platforms.get_selection().selected_foreach((model, path, iter) => {
  214. Value? platform;
  215. model.get_value(iter, 0, out platform);
  216. string key = platform_property(((TargetPlatform)platform).to_key(), property_names[i]);
  217. bool init = properties[i].get_data<bool>("init");
  218. // Try <platform>.<property> first. Fallback to <property>.
  219. if (!_texture_database.has_property(_texture_id, key))
  220. key = property_names[i];
  221. if (_texture_database.has_property(_texture_id, key)) {
  222. Value? val = _texture_database.get_property(_texture_id, key);
  223. if (!init) {
  224. properties[i].set_data("init", true);
  225. properties[i].set_generic_value(val);
  226. properties[i].set_inconsistent(false);
  227. } else if (!are_values_equal(val, properties[i].generic_value())) {
  228. properties[i].set_inconsistent(true);
  229. }
  230. } else {
  231. properties[i].set_inconsistent(true);
  232. if (!init) {
  233. properties[i].set_data("init", true);
  234. }
  235. }
  236. });
  237. }
  238. }
  239. public void on_format_value_changed()
  240. {
  241. on_property_value_changed("format", _format);
  242. }
  243. public void on_generate_mips_value_changed()
  244. {
  245. on_property_value_changed("generate_mips", _generate_mips);
  246. }
  247. public void on_mip_skip_smallest_value_changed()
  248. {
  249. on_property_value_changed("mip_skip_smallest", _mip_skip_smallest);
  250. }
  251. public void on_normal_map_value_changed()
  252. {
  253. on_property_value_changed("normal_map", _normal_map);
  254. }
  255. public void on_property_value_changed(string property_name, Property property_value)
  256. {
  257. if (_texture_id == GUID_ZERO)
  258. return;
  259. Value? val = property_value.generic_value();
  260. // For backward compatibility.
  261. if (property_name == "generate_mips" || property_name == "normal_map") {
  262. if (_texture_database.has_property(_texture_id, property_name))
  263. _texture_database.set_property(_texture_id, property_name, val);
  264. }
  265. _platforms.get_selection().selected_foreach((model, path, iter) => {
  266. Value? platform;
  267. model.get_value(iter, 0, out platform);
  268. string key = platform_property(((TargetPlatform)platform).to_key(), property_name);
  269. _texture_database.set_property(_texture_id, key, val);
  270. });
  271. }
  272. public void save()
  273. {
  274. if (_texture_id == GUID_ZERO)
  275. return;
  276. _texture_database.dump(_project.absolute_path(_texture_path), _texture_id);
  277. texture_saved();
  278. }
  279. public bool on_delete_event(Gdk.EventAny ev)
  280. {
  281. save();
  282. return Gdk.EVENT_PROPAGATE;
  283. }
  284. public string platform_property(string platform_name, string property)
  285. {
  286. return "output."
  287. + platform_name
  288. + "."
  289. + property
  290. ;
  291. }
  292. }
  293. } /* namespace Crown */