colladaImport.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "console/engineAPI.h"
  24. #include "core/volume.h"
  25. #include "ts/collada/colladaUtils.h"
  26. #include "ts/collada/colladaAppNode.h"
  27. #include "ts/collada/colladaShapeLoader.h"
  28. #include "gui/controls/guiTreeViewCtrl.h"
  29. // Helper struct for counting nodes, meshes and polygons down through the scene
  30. // hierarchy
  31. struct SceneStats
  32. {
  33. S32 numNodes;
  34. S32 numMeshes;
  35. S32 numPolygons;
  36. S32 numMaterials;
  37. S32 numLights;
  38. S32 numClips;
  39. SceneStats() : numNodes(0), numMeshes(0), numPolygons(0), numMaterials(0), numLights(0), numClips(0) { }
  40. };
  41. // Recurse through the <visual_scene> adding nodes and geometry to the GuiTreeView control
  42. static void processNode(GuiTreeViewCtrl* tree, domNode* node, S32 parentID, SceneStats& stats)
  43. {
  44. stats.numNodes++;
  45. S32 nodeID = tree->insertItem(parentID, _GetNameOrId(node), "node", "", 0, 0);
  46. // Update mesh and poly counts
  47. for (S32 i = 0; i < node->getContents().getCount(); i++)
  48. {
  49. domGeometry* geom = 0;
  50. const char* elemName = "";
  51. daeElement* child = node->getContents()[i];
  52. switch (child->getElementType())
  53. {
  54. case COLLADA_TYPE::INSTANCE_GEOMETRY:
  55. {
  56. domInstance_geometry* instgeom = daeSafeCast<domInstance_geometry>(child);
  57. if (instgeom)
  58. {
  59. geom = daeSafeCast<domGeometry>(instgeom->getUrl().getElement());
  60. elemName = _GetNameOrId(geom);
  61. }
  62. break;
  63. }
  64. case COLLADA_TYPE::INSTANCE_CONTROLLER:
  65. {
  66. domInstance_controller* instctrl = daeSafeCast<domInstance_controller>(child);
  67. if (instctrl)
  68. {
  69. domController* ctrl = daeSafeCast<domController>(instctrl->getUrl().getElement());
  70. elemName = _GetNameOrId(ctrl);
  71. if (ctrl && ctrl->getSkin())
  72. geom = daeSafeCast<domGeometry>(ctrl->getSkin()->getSource().getElement());
  73. else if (ctrl && ctrl->getMorph())
  74. geom = daeSafeCast<domGeometry>(ctrl->getMorph()->getSource().getElement());
  75. }
  76. break;
  77. }
  78. case COLLADA_TYPE::INSTANCE_LIGHT:
  79. stats.numLights++;
  80. tree->insertItem(nodeID, _GetNameOrId(node), "light", "", 0, 0);
  81. break;
  82. }
  83. if (geom && geom->getMesh())
  84. {
  85. const char* name = _GetNameOrId(node);
  86. if ( dStrEqual( name, "null" ) || dStrEndsWith( name, "PIVOT" ) )
  87. name = _GetNameOrId( daeSafeCast<domNode>(node->getParent()) );
  88. stats.numMeshes++;
  89. tree->insertItem(nodeID, name, "mesh", "", 0, 0);
  90. for (S32 j = 0; j < geom->getMesh()->getTriangles_array().getCount(); j++)
  91. stats.numPolygons += geom->getMesh()->getTriangles_array()[j]->getCount();
  92. for (S32 j = 0; j < geom->getMesh()->getTristrips_array().getCount(); j++)
  93. stats.numPolygons += geom->getMesh()->getTristrips_array()[j]->getCount();
  94. for (S32 j = 0; j < geom->getMesh()->getTrifans_array().getCount(); j++)
  95. stats.numPolygons += geom->getMesh()->getTrifans_array()[j]->getCount();
  96. for (S32 j = 0; j < geom->getMesh()->getPolygons_array().getCount(); j++)
  97. stats.numPolygons += geom->getMesh()->getPolygons_array()[j]->getCount();
  98. for (S32 j = 0; j < geom->getMesh()->getPolylist_array().getCount(); j++)
  99. stats.numPolygons += geom->getMesh()->getPolylist_array()[j]->getCount();
  100. }
  101. }
  102. // Recurse into child nodes
  103. for (S32 i = 0; i < node->getNode_array().getCount(); i++)
  104. processNode(tree, node->getNode_array()[i], nodeID, stats);
  105. for (S32 i = 0; i < node->getInstance_node_array().getCount(); i++)
  106. {
  107. domInstance_node* instnode = node->getInstance_node_array()[i];
  108. domNode* node = daeSafeCast<domNode>(instnode->getUrl().getElement());
  109. if (node)
  110. processNode(tree, node, nodeID, stats);
  111. }
  112. }
  113. DefineConsoleFunction( enumColladaForImport, bool, (const char * shapePath, const char * ctrl), ,
  114. "(string shapePath, GuiTreeViewCtrl ctrl) Collect scene information from "
  115. "a COLLADA file and store it in a GuiTreeView control. This function is "
  116. "used by the COLLADA import gui to show a preview of the scene contents "
  117. "prior to import, and is probably not much use for anything else.\n"
  118. "@param shapePath COLLADA filename\n"
  119. "@param ctrl GuiTreeView control to add elements to\n"
  120. "@return true if successful, false otherwise\n"
  121. "@ingroup Editors\n"
  122. "@internal")
  123. {
  124. GuiTreeViewCtrl* tree;
  125. if (!Sim::findObject(ctrl, tree))
  126. {
  127. Con::errorf("enumColladaScene::Could not find GuiTreeViewCtrl '%s'", ctrl);
  128. return false;
  129. }
  130. // Check if a cached DTS is available => no need to import the collada file
  131. // if we can load the DTS instead
  132. Torque::Path path(shapePath);
  133. if (ColladaShapeLoader::canLoadCachedDTS(path))
  134. return false;
  135. // Check if this is a Sketchup file (.kmz) and if so, mount the zip filesystem
  136. // and get the path to the DAE file.
  137. String mountPoint;
  138. Torque::Path daePath;
  139. bool isSketchup = ColladaShapeLoader::checkAndMountSketchup(path, mountPoint, daePath);
  140. // Load the Collada file into memory
  141. domCOLLADA* root = ColladaShapeLoader::getDomCOLLADA(daePath);
  142. if (!root)
  143. {
  144. TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Load complete");
  145. return false;
  146. }
  147. if (isSketchup)
  148. {
  149. // Unmount the zip if we mounted it
  150. Torque::FS::Unmount(mountPoint);
  151. }
  152. // Initialize tree
  153. tree->removeItem(0);
  154. S32 nodesID = tree->insertItem(0, "Shape", "", "", 0, 0);
  155. S32 matsID = tree->insertItem(0, "Materials", "", "", 0, 0);
  156. S32 animsID = tree->insertItem(0, "Animations", "", "", 0, 0);
  157. SceneStats stats;
  158. // Query DOM for shape summary details
  159. for (S32 i = 0; i < root->getLibrary_visual_scenes_array().getCount(); i++)
  160. {
  161. const domLibrary_visual_scenes* libScenes = root->getLibrary_visual_scenes_array()[i];
  162. for (S32 j = 0; j < libScenes->getVisual_scene_array().getCount(); j++)
  163. {
  164. const domVisual_scene* visualScene = libScenes->getVisual_scene_array()[j];
  165. for (S32 k = 0; k < visualScene->getNode_array().getCount(); k++)
  166. processNode(tree, visualScene->getNode_array()[k], nodesID, stats);
  167. }
  168. }
  169. // Get material count
  170. for (S32 i = 0; i < root->getLibrary_materials_array().getCount(); i++)
  171. {
  172. const domLibrary_materials* libraryMats = root->getLibrary_materials_array()[i];
  173. stats.numMaterials += libraryMats->getMaterial_array().getCount();
  174. for (S32 j = 0; j < libraryMats->getMaterial_array().getCount(); j++)
  175. {
  176. domMaterial* mat = libraryMats->getMaterial_array()[j];
  177. tree->insertItem(matsID, _GetNameOrId(mat), _GetNameOrId(mat), "", 0, 0);
  178. }
  179. }
  180. // Get animation count
  181. for (S32 i = 0; i < root->getLibrary_animation_clips_array().getCount(); i++)
  182. {
  183. const domLibrary_animation_clips* libraryClips = root->getLibrary_animation_clips_array()[i];
  184. stats.numClips += libraryClips->getAnimation_clip_array().getCount();
  185. for (S32 j = 0; j < libraryClips->getAnimation_clip_array().getCount(); j++)
  186. {
  187. domAnimation_clip* clip = libraryClips->getAnimation_clip_array()[j];
  188. tree->insertItem(animsID, _GetNameOrId(clip), "animation", "", 0, 0);
  189. }
  190. }
  191. if (stats.numClips == 0)
  192. {
  193. // No clips => check if there are any animations (these will be added to a default clip)
  194. for (S32 i = 0; i < root->getLibrary_animations_array().getCount(); i++)
  195. {
  196. const domLibrary_animations* libraryAnims = root->getLibrary_animations_array()[i];
  197. if (libraryAnims->getAnimation_array().getCount())
  198. {
  199. stats.numClips = 1;
  200. tree->insertItem(animsID, "ambient", "animation", "", 0, 0);
  201. break;
  202. }
  203. }
  204. }
  205. // Extract the global scale and up_axis from the top level <asset> element,
  206. F32 unit = 1.0f;
  207. domUpAxisType upAxis = UPAXISTYPE_Z_UP;
  208. if (root->getAsset()) {
  209. if (root->getAsset()->getUnit())
  210. unit = root->getAsset()->getUnit()->getMeter();
  211. if (root->getAsset()->getUp_axis())
  212. upAxis = root->getAsset()->getUp_axis()->getValue();
  213. }
  214. TSShapeLoader::updateProgress(TSShapeLoader::Load_Complete, "Load complete");
  215. // Store shape information in the tree control
  216. tree->setDataField(StringTable->insert("_nodeCount"), 0, avar("%d", stats.numNodes));
  217. tree->setDataField(StringTable->insert("_meshCount"), 0, avar("%d", stats.numMeshes));
  218. tree->setDataField(StringTable->insert("_polygonCount"), 0, avar("%d", stats.numPolygons));
  219. tree->setDataField(StringTable->insert("_materialCount"), 0, avar("%d", stats.numMaterials));
  220. tree->setDataField(StringTable->insert("_lightCount"), 0, avar("%d", stats.numLights));
  221. tree->setDataField(StringTable->insert("_animCount"), 0, avar("%d", stats.numClips));
  222. tree->setDataField(StringTable->insert("_unit"), 0, avar("%g", unit));
  223. if (upAxis == UPAXISTYPE_X_UP)
  224. tree->setDataField(StringTable->insert("_upAxis"), 0, "X_AXIS");
  225. else if (upAxis == UPAXISTYPE_Y_UP)
  226. tree->setDataField(StringTable->insert("_upAxis"), 0, "Y_AXIS");
  227. else
  228. tree->setDataField(StringTable->insert("_upAxis"), 0, "Z_AXIS");
  229. return true;
  230. }