mesh_resource.vala 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * Copyright (c) 2012-2026 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: GPL-3.0-or-later
  4. */
  5. namespace Crown
  6. {
  7. namespace MeshResource
  8. {
  9. public static void create_components(Database db, Guid parent_unit_id, Guid unit_id, string material_name, string resource_name, string node_name, Hashtable node)
  10. {
  11. Unit unit = Unit(db, unit_id);
  12. Matrix4x4 matrix_local = Matrix4x4.from_array((Gee.ArrayList<Value?>)node["matrix_local"]);
  13. Vector3 position = matrix_local.t.to_vector3();
  14. Quaternion rotation = matrix_local.rotation();
  15. Vector3 scale = matrix_local.scale();
  16. // Create transform
  17. {
  18. Guid component_id;
  19. if (!unit.has_component(out component_id, OBJECT_TYPE_TRANSFORM)) {
  20. component_id = Guid.new_guid();
  21. db.create(component_id, OBJECT_TYPE_TRANSFORM);
  22. db.add_to_set(unit_id, "components", component_id);
  23. }
  24. unit.set_component_vector3 (component_id, "data.position", position);
  25. unit.set_component_quaternion(component_id, "data.rotation", rotation);
  26. unit.set_component_vector3 (component_id, "data.scale", scale);
  27. unit.set_component_string (component_id, "data.name", node_name);
  28. }
  29. // Create mesh_renderer
  30. {
  31. Guid component_id;
  32. if (!unit.has_component(out component_id, OBJECT_TYPE_MESH_RENDERER)) {
  33. component_id = Guid.new_guid();
  34. db.create(component_id, OBJECT_TYPE_MESH_RENDERER);
  35. db.add_to_set(unit_id, "components", component_id);
  36. }
  37. unit.set_component_string(component_id, "data.geometry_name", node_name);
  38. unit.set_component_string(component_id, "data.material", material_name);
  39. unit.set_component_string(component_id, "data.mesh_resource", resource_name);
  40. unit.set_component_bool (component_id, "data.visible", true);
  41. }
  42. // Create collider
  43. {
  44. Guid component_id;
  45. if (!unit.has_component(out component_id, OBJECT_TYPE_COLLIDER)) {
  46. component_id = Guid.new_guid();
  47. db.create(component_id, OBJECT_TYPE_COLLIDER);
  48. db.add_to_set(unit_id, "components", component_id);
  49. }
  50. unit.set_component_string(component_id, "data.shape", "mesh");
  51. unit.set_component_string(component_id, "data.scene", resource_name);
  52. unit.set_component_string(component_id, "data.name", node_name);
  53. }
  54. // Create actor
  55. {
  56. Guid component_id;
  57. if (!unit.has_component(out component_id, OBJECT_TYPE_ACTOR)) {
  58. component_id = Guid.new_guid();
  59. db.create(component_id, OBJECT_TYPE_ACTOR);
  60. db.add_to_set(unit_id, "components", component_id);
  61. }
  62. unit.set_component_string(component_id, "data.class", "static");
  63. unit.set_component_string(component_id, "data.collision_filter", "default");
  64. unit.set_component_double(component_id, "data.mass", 10);
  65. unit.set_component_string(component_id, "data.material", "default");
  66. }
  67. if (parent_unit_id != unit_id)
  68. db.add_to_set(parent_unit_id, "children", unit_id);
  69. if (node.has_key("children")) {
  70. Hashtable children = (Hashtable)node["children"];
  71. foreach (var child in children.entries) {
  72. Guid new_unit_id = Guid.new_guid();
  73. db.create(new_unit_id, OBJECT_TYPE_UNIT);
  74. create_components(db, unit_id, new_unit_id, material_name, resource_name, child.key, (Hashtable)child.value);
  75. }
  76. }
  77. }
  78. public static ImportResult do_import(Database database, string destination_dir, SList<string> filenames)
  79. {
  80. Project project = database._project;
  81. foreach (unowned string filename_i in filenames) {
  82. GLib.File file_src = File.new_for_path(filename_i);
  83. GLib.File file_dst = File.new_for_path(Path.build_filename(destination_dir, file_src.get_basename()));
  84. string resource_filename = project.resource_filename(file_dst.get_path());
  85. string resource_path = ResourceId.normalize(resource_filename);
  86. string resource_name = ResourceId.name(resource_path);
  87. Database db = new Database(project);
  88. string material_name = resource_name;
  89. MaterialResource material_resource = MaterialResource.mesh(db, Guid.new_guid());
  90. if (material_resource.save(project, material_name) != 0)
  91. return ImportResult.ERROR;
  92. try {
  93. file_src.copy(file_dst, FileCopyFlags.OVERWRITE);
  94. } catch (Error e) {
  95. loge(e.message);
  96. return ImportResult.ERROR;
  97. }
  98. // Generate or modify existing .unit.
  99. Guid unit_id;
  100. if (db.add_from_resource_path(out unit_id, resource_name + ".unit") != 0) {
  101. unit_id = Guid.new_guid();
  102. db.create(unit_id, OBJECT_TYPE_UNIT);
  103. }
  104. try {
  105. Hashtable mesh = SJSON.load_from_path(filename_i);
  106. Hashtable mesh_nodes = (Hashtable)mesh["nodes"];
  107. if (mesh_nodes.size > 1) {
  108. // Create an extra "root" unit to accommodate multiple root objects. This
  109. // "root" unit will only have a transform centered at origin to allow other
  110. // objects to be linked to it via the SceneGraph.
  111. Unit unit = Unit(db, unit_id);
  112. Guid component_id;
  113. if (!unit.has_component(out component_id, OBJECT_TYPE_TRANSFORM)) {
  114. component_id = Guid.new_guid();
  115. db.create(component_id, OBJECT_TYPE_TRANSFORM);
  116. db.add_to_set(unit_id, "components", component_id);
  117. }
  118. unit.set_component_vector3 (component_id, "data.position", VECTOR3_ZERO);
  119. unit.set_component_quaternion(component_id, "data.rotation", QUATERNION_IDENTITY);
  120. unit.set_component_vector3 (component_id, "data.scale", VECTOR3_ONE);
  121. }
  122. Guid new_unit_id = unit_id;
  123. foreach (var entry in mesh_nodes.entries) {
  124. if (mesh_nodes.size > 1) {
  125. // If the mesh contains multiple root objects, create a new unit for each
  126. // one of those, otherwise put the components inside the base unit.
  127. new_unit_id = Guid.new_guid();
  128. db.create(new_unit_id, OBJECT_TYPE_UNIT);
  129. }
  130. create_components(db
  131. , unit_id
  132. , new_unit_id
  133. , material_name
  134. , resource_name
  135. , entry.key
  136. , (Hashtable)entry.value
  137. );
  138. }
  139. if (db.save(project.absolute_path(resource_name) + ".unit", unit_id) != 0)
  140. return ImportResult.ERROR;
  141. } catch (JsonSyntaxError e) {
  142. loge(e.message);
  143. return ImportResult.ERROR;
  144. }
  145. }
  146. return ImportResult.SUCCESS;
  147. }
  148. public static void import(Import import_result, Database database, string destination_dir, SList<string> filenames, Gtk.Window? parent_window)
  149. {
  150. SList<string> fbx_filenames = new SList<string>();
  151. SList<string> mesh_filenames = new SList<string>();
  152. foreach (unowned string filename_i in filenames) {
  153. string fi = filename_i.down();
  154. if (fi.has_suffix(".fbx"))
  155. fbx_filenames.append(filename_i);
  156. else if (fi.has_suffix(".mesh"))
  157. mesh_filenames.append(filename_i);
  158. else
  159. assert(false);
  160. }
  161. ImportResult res = ImportResult.SUCCESS;
  162. if (mesh_filenames != null)
  163. res = MeshResource.do_import(database, destination_dir, mesh_filenames);
  164. if (res == ImportResult.SUCCESS && fbx_filenames != null)
  165. FBXImporter.import(import_result, database, destination_dir, fbx_filenames, parent_window);
  166. else
  167. import_result(res);
  168. }
  169. } /* namespace MeshResource */
  170. } /* namespace Crown */