Source: formats/collada/ColladaLoader.js

  1. /*
  2. * Copyright 2003-2006, 2009, 2017, 2020 United States Government, as represented
  3. * by the Administrator of the National Aeronautics and Space Administration.
  4. * All rights reserved.
  5. *
  6. * The NASAWorldWind/WebWorldWind platform is licensed under the Apache License,
  7. * Version 2.0 (the "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License
  9. * at http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software distributed
  12. * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  13. * CONDITIONS OF ANY KIND, either express or implied. See the License for the
  14. * specific language governing permissions and limitations under the License.
  15. *
  16. * NASAWorldWind/WebWorldWind also contains the following 3rd party Open Source
  17. * software:
  18. *
  19. * ES6-Promise – under MIT License
  20. * libtess.js – SGI Free Software License B
  21. * Proj4 – under MIT License
  22. * JSZip – under MIT License
  23. *
  24. * A complete listing of 3rd Party software notices and licenses included in
  25. * WebWorldWind can be found in the WebWorldWind 3rd-party notices and licenses
  26. * PDF found in code directory.
  27. */
  28. /**
  29. * @exports ColladaLoader
  30. */
  31. define([
  32. '../../error/ArgumentError',
  33. './ColladaAsset',
  34. './ColladaImage',
  35. './ColladaMaterial',
  36. './ColladaMesh',
  37. './ColladaNode',
  38. './ColladaScene',
  39. './ColladaUtils',
  40. '../../util/Logger'
  41. ],
  42. function (ArgumentError,
  43. ColladaAsset,
  44. ColladaImage,
  45. ColladaMaterial,
  46. ColladaMesh,
  47. ColladaNode,
  48. ColladaScene,
  49. ColladaUtils,
  50. Logger) {
  51. "use strict";
  52. /**
  53. * Constructs a ColladaLoader
  54. * @alias ColladaLoader
  55. * @constructor
  56. * @classdesc Represents a Collada Loader. Fetches and parses a collada document and returns the
  57. * necessary information to render the collada model.
  58. * @param {Position} position The model's geographic position.
  59. * @param {Object} config Configuration options for the loader.
  60. * <ul>
  61. * <li>dirPath - the path to the directory where the collada file is located</li>
  62. * </ul>
  63. */
  64. var ColladaLoader = function (position, config) {
  65. if (!position) {
  66. throw new ArgumentError(
  67. Logger.logMessage(Logger.LEVEL_SEVERE, "ColladaLoader", "constructor", "missingPosition"));
  68. }
  69. this.position = position;
  70. this.dirPath = '/';
  71. this.init(config);
  72. };
  73. /**
  74. * Initialization of the ColladaLoader
  75. * @param {Object} config Configuration options for the loader.
  76. * <ul>
  77. * <li>dirPath - the path to the directory where the collada file is located</li>
  78. * </ul>
  79. */
  80. ColladaLoader.prototype.init = function (config) {
  81. if (config) {
  82. this.dirPath = config.dirPath || '/';
  83. }
  84. this.scene = {
  85. type: "SceneTree",
  86. dirPath: this.dirPath,
  87. images: {},
  88. metadata: {},
  89. materials: {},
  90. meshes: {},
  91. root: {children: []}
  92. };
  93. this.xmlDoc = null;
  94. };
  95. /**
  96. * Fetches and parses a collada file
  97. * @param {String} url The url to the collada .dae file.
  98. * @param {Function} cb A callback function to call with the result when the parsing is done.
  99. * @returns {ColladaScene} A renderable shape.
  100. */
  101. ColladaLoader.prototype.load = function (url, cb) {
  102. if (url.indexOf("://") === -1) {
  103. url = this.dirPath + url;
  104. }
  105. ColladaUtils.fetchFile(url, function (data) {
  106. if (!data) {
  107. var colladaScene = null;
  108. } else {
  109. try {
  110. colladaScene = this.parse(data);
  111. } catch (e) {
  112. colladaScene = null;
  113. Logger.log(Logger.LEVEL_SEVERE, "error parsing collada file: " + e);
  114. }
  115. }
  116. cb(colladaScene);
  117. }.bind(this));
  118. };
  119. /**
  120. * Parses a collada file
  121. * @param {XML} data The raw XML data of the collada file.
  122. * @returns {ColladaScene} A renderable shape.
  123. */
  124. ColladaLoader.prototype.parse = function (data) {
  125. this.init();
  126. var parser = new DOMParser();
  127. this.xmlDoc = parser.parseFromString(data, "text/xml");
  128. var iNodes = this.xmlDoc.querySelectorAll('library_nodes node');
  129. var eNodes = this.xmlDoc.querySelectorAll("library_effects effect");
  130. this.scene.metadata = (new ColladaAsset(this.xmlDoc)).parse();
  131. this.parseLib('visual_scene', iNodes);
  132. this.parseLib('library_geometries');
  133. this.parseLib('library_materials', eNodes);
  134. this.parseLib('library_images');
  135. this.xmlDoc = null;
  136. return new ColladaScene(this.position, this.scene);
  137. };
  138. /**
  139. * Parses a collada library tag.
  140. * @param {String} libName The library tag name.
  141. * @param {NodeList} extraNodes Nodes from library_nodes or effects form library_effects
  142. */
  143. ColladaLoader.prototype.parseLib = function (libName, extraNodes) {
  144. var libs = this.xmlDoc.getElementsByTagName(libName);
  145. var libNodes = [];
  146. if (libs && libs.length) {
  147. libNodes = libs[0].childNodes;
  148. }
  149. for (var i = 0; i < libNodes.length; i++) {
  150. var libNode = libNodes[i];
  151. if (libNode.nodeType !== 1) {
  152. continue;
  153. }
  154. switch (libNode.nodeName) {
  155. case 'node':
  156. var nodes = (new ColladaNode()).parse(libNode, extraNodes);
  157. if (nodes) {
  158. for (var j = 0, len = nodes.length; j < len; j++) {
  159. this.scene.root.children.push(nodes[j]);
  160. }
  161. }
  162. break;
  163. case 'geometry':
  164. var geometryId = libNode.getAttribute("id");
  165. var xmlMesh = libNode.querySelector("mesh");
  166. var mesh = (new ColladaMesh(geometryId)).parse(xmlMesh);
  167. if (mesh) {
  168. this.scene.meshes[geometryId] = mesh;
  169. }
  170. break;
  171. case 'material':
  172. var materialId = libNode.getAttribute("id");
  173. var iEffect = libNode.querySelector("instance_effect");
  174. var effectId = iEffect.getAttribute("url").substr(1);
  175. var effect = ColladaUtils.querySelectorById(extraNodes, effectId);
  176. var material = (new ColladaMaterial(materialId)).parse(effect);
  177. if (material) {
  178. this.scene.materials[materialId] = material;
  179. }
  180. break;
  181. case 'image':
  182. var imageId = libNode.getAttribute("id");
  183. var imageName = libNode.getAttribute("name");
  184. var image = (new ColladaImage(imageId, imageName)).parse(libNode);
  185. if (image) {
  186. this.scene.images[imageId] = image;
  187. }
  188. break;
  189. default:
  190. break;
  191. }
  192. }
  193. };
  194. return ColladaLoader;
  195. });