decodeDraco.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. define(['./ComponentDatatype-cf1fa08e', './defaultValue-fe22d8c0', './IndexDatatype-2643aa47', './RuntimeError-ef395448', './createTaskProcessorWorker', './Check-6ede7e26', './WebGLConstants-0b1ce7ba', './Math-0a2ac845'], (function (ComponentDatatype, defaultValue, IndexDatatype, RuntimeError, createTaskProcessorWorker, Check, WebGLConstants, Math) { 'use strict';
  2. /* global require */
  3. let draco;
  4. function decodeIndexArray(dracoGeometry, dracoDecoder) {
  5. const numPoints = dracoGeometry.num_points();
  6. const numFaces = dracoGeometry.num_faces();
  7. const faceIndices = new draco.DracoInt32Array();
  8. const numIndices = numFaces * 3;
  9. const indexArray = IndexDatatype.IndexDatatype.createTypedArray(numPoints, numIndices);
  10. let offset = 0;
  11. for (let i = 0; i < numFaces; ++i) {
  12. dracoDecoder.GetFaceFromMesh(dracoGeometry, i, faceIndices);
  13. indexArray[offset + 0] = faceIndices.GetValue(0);
  14. indexArray[offset + 1] = faceIndices.GetValue(1);
  15. indexArray[offset + 2] = faceIndices.GetValue(2);
  16. offset += 3;
  17. }
  18. draco.destroy(faceIndices);
  19. return {
  20. typedArray: indexArray,
  21. numberOfIndices: numIndices,
  22. };
  23. }
  24. function decodeQuantizedDracoTypedArray(
  25. dracoGeometry,
  26. dracoDecoder,
  27. dracoAttribute,
  28. quantization,
  29. vertexArrayLength
  30. ) {
  31. let vertexArray;
  32. let attributeData;
  33. if (quantization.quantizationBits <= 8) {
  34. attributeData = new draco.DracoUInt8Array();
  35. vertexArray = new Uint8Array(vertexArrayLength);
  36. dracoDecoder.GetAttributeUInt8ForAllPoints(
  37. dracoGeometry,
  38. dracoAttribute,
  39. attributeData
  40. );
  41. } else if (quantization.quantizationBits <= 16) {
  42. attributeData = new draco.DracoUInt16Array();
  43. vertexArray = new Uint16Array(vertexArrayLength);
  44. dracoDecoder.GetAttributeUInt16ForAllPoints(
  45. dracoGeometry,
  46. dracoAttribute,
  47. attributeData
  48. );
  49. } else {
  50. attributeData = new draco.DracoFloat32Array();
  51. vertexArray = new Float32Array(vertexArrayLength);
  52. dracoDecoder.GetAttributeFloatForAllPoints(
  53. dracoGeometry,
  54. dracoAttribute,
  55. attributeData
  56. );
  57. }
  58. for (let i = 0; i < vertexArrayLength; ++i) {
  59. vertexArray[i] = attributeData.GetValue(i);
  60. }
  61. draco.destroy(attributeData);
  62. return vertexArray;
  63. }
  64. function decodeDracoTypedArray(
  65. dracoGeometry,
  66. dracoDecoder,
  67. dracoAttribute,
  68. vertexArrayLength
  69. ) {
  70. let vertexArray;
  71. let attributeData;
  72. // Some attribute types are casted down to 32 bit since Draco only returns 32 bit values
  73. switch (dracoAttribute.data_type()) {
  74. case 1:
  75. case 11: // DT_INT8 or DT_BOOL
  76. attributeData = new draco.DracoInt8Array();
  77. vertexArray = new Int8Array(vertexArrayLength);
  78. dracoDecoder.GetAttributeInt8ForAllPoints(
  79. dracoGeometry,
  80. dracoAttribute,
  81. attributeData
  82. );
  83. break;
  84. case 2: // DT_UINT8
  85. attributeData = new draco.DracoUInt8Array();
  86. vertexArray = new Uint8Array(vertexArrayLength);
  87. dracoDecoder.GetAttributeUInt8ForAllPoints(
  88. dracoGeometry,
  89. dracoAttribute,
  90. attributeData
  91. );
  92. break;
  93. case 3: // DT_INT16
  94. attributeData = new draco.DracoInt16Array();
  95. vertexArray = new Int16Array(vertexArrayLength);
  96. dracoDecoder.GetAttributeInt16ForAllPoints(
  97. dracoGeometry,
  98. dracoAttribute,
  99. attributeData
  100. );
  101. break;
  102. case 4: // DT_UINT16
  103. attributeData = new draco.DracoUInt16Array();
  104. vertexArray = new Uint16Array(vertexArrayLength);
  105. dracoDecoder.GetAttributeUInt16ForAllPoints(
  106. dracoGeometry,
  107. dracoAttribute,
  108. attributeData
  109. );
  110. break;
  111. case 5:
  112. case 7: // DT_INT32 or DT_INT64
  113. attributeData = new draco.DracoInt32Array();
  114. vertexArray = new Int32Array(vertexArrayLength);
  115. dracoDecoder.GetAttributeInt32ForAllPoints(
  116. dracoGeometry,
  117. dracoAttribute,
  118. attributeData
  119. );
  120. break;
  121. case 6:
  122. case 8: // DT_UINT32 or DT_UINT64
  123. attributeData = new draco.DracoUInt32Array();
  124. vertexArray = new Uint32Array(vertexArrayLength);
  125. dracoDecoder.GetAttributeUInt32ForAllPoints(
  126. dracoGeometry,
  127. dracoAttribute,
  128. attributeData
  129. );
  130. break;
  131. case 9:
  132. case 10: // DT_FLOAT32 or DT_FLOAT64
  133. attributeData = new draco.DracoFloat32Array();
  134. vertexArray = new Float32Array(vertexArrayLength);
  135. dracoDecoder.GetAttributeFloatForAllPoints(
  136. dracoGeometry,
  137. dracoAttribute,
  138. attributeData
  139. );
  140. break;
  141. }
  142. for (let i = 0; i < vertexArrayLength; ++i) {
  143. vertexArray[i] = attributeData.GetValue(i);
  144. }
  145. draco.destroy(attributeData);
  146. return vertexArray;
  147. }
  148. function decodeAttribute(dracoGeometry, dracoDecoder, dracoAttribute) {
  149. const numPoints = dracoGeometry.num_points();
  150. const numComponents = dracoAttribute.num_components();
  151. let quantization;
  152. let transform = new draco.AttributeQuantizationTransform();
  153. if (transform.InitFromAttribute(dracoAttribute)) {
  154. const minValues = new Array(numComponents);
  155. for (let i = 0; i < numComponents; ++i) {
  156. minValues[i] = transform.min_value(i);
  157. }
  158. quantization = {
  159. quantizationBits: transform.quantization_bits(),
  160. minValues: minValues,
  161. range: transform.range(),
  162. octEncoded: false,
  163. };
  164. }
  165. draco.destroy(transform);
  166. transform = new draco.AttributeOctahedronTransform();
  167. if (transform.InitFromAttribute(dracoAttribute)) {
  168. quantization = {
  169. quantizationBits: transform.quantization_bits(),
  170. octEncoded: true,
  171. };
  172. }
  173. draco.destroy(transform);
  174. const vertexArrayLength = numPoints * numComponents;
  175. let vertexArray;
  176. if (defaultValue.defined(quantization)) {
  177. vertexArray = decodeQuantizedDracoTypedArray(
  178. dracoGeometry,
  179. dracoDecoder,
  180. dracoAttribute,
  181. quantization,
  182. vertexArrayLength
  183. );
  184. } else {
  185. vertexArray = decodeDracoTypedArray(
  186. dracoGeometry,
  187. dracoDecoder,
  188. dracoAttribute,
  189. vertexArrayLength
  190. );
  191. }
  192. const componentDatatype = ComponentDatatype.ComponentDatatype.fromTypedArray(vertexArray);
  193. return {
  194. array: vertexArray,
  195. data: {
  196. componentsPerAttribute: numComponents,
  197. componentDatatype: componentDatatype,
  198. byteOffset: dracoAttribute.byte_offset(),
  199. byteStride:
  200. ComponentDatatype.ComponentDatatype.getSizeInBytes(componentDatatype) * numComponents,
  201. normalized: dracoAttribute.normalized(),
  202. quantization: quantization,
  203. },
  204. };
  205. }
  206. function decodePointCloud(parameters) {
  207. const dracoDecoder = new draco.Decoder();
  208. if (parameters.dequantizeInShader) {
  209. dracoDecoder.SkipAttributeTransform(draco.POSITION);
  210. dracoDecoder.SkipAttributeTransform(draco.NORMAL);
  211. }
  212. const buffer = new draco.DecoderBuffer();
  213. buffer.Init(parameters.buffer, parameters.buffer.length);
  214. const geometryType = dracoDecoder.GetEncodedGeometryType(buffer);
  215. if (geometryType !== draco.POINT_CLOUD) {
  216. throw new RuntimeError.RuntimeError("Draco geometry type must be POINT_CLOUD.");
  217. }
  218. const dracoPointCloud = new draco.PointCloud();
  219. const decodingStatus = dracoDecoder.DecodeBufferToPointCloud(
  220. buffer,
  221. dracoPointCloud
  222. );
  223. if (!decodingStatus.ok() || dracoPointCloud.ptr === 0) {
  224. throw new RuntimeError.RuntimeError(
  225. `Error decoding draco point cloud: ${decodingStatus.error_msg()}`
  226. );
  227. }
  228. draco.destroy(buffer);
  229. const result = {};
  230. const properties = parameters.properties;
  231. for (const propertyName in properties) {
  232. if (properties.hasOwnProperty(propertyName)) {
  233. let dracoAttribute;
  234. if (propertyName === "POSITION" || propertyName === "NORMAL") {
  235. const dracoAttributeId = dracoDecoder.GetAttributeId(
  236. dracoPointCloud,
  237. draco[propertyName]
  238. );
  239. dracoAttribute = dracoDecoder.GetAttribute(
  240. dracoPointCloud,
  241. dracoAttributeId
  242. );
  243. } else {
  244. const attributeId = properties[propertyName];
  245. dracoAttribute = dracoDecoder.GetAttributeByUniqueId(
  246. dracoPointCloud,
  247. attributeId
  248. );
  249. }
  250. result[propertyName] = decodeAttribute(
  251. dracoPointCloud,
  252. dracoDecoder,
  253. dracoAttribute
  254. );
  255. }
  256. }
  257. draco.destroy(dracoPointCloud);
  258. draco.destroy(dracoDecoder);
  259. return result;
  260. }
  261. function decodePrimitive(parameters) {
  262. const dracoDecoder = new draco.Decoder();
  263. // Skip all parameter types except generic
  264. const attributesToSkip = ["POSITION", "NORMAL", "COLOR", "TEX_COORD"];
  265. if (parameters.dequantizeInShader) {
  266. for (let i = 0; i < attributesToSkip.length; ++i) {
  267. dracoDecoder.SkipAttributeTransform(draco[attributesToSkip[i]]);
  268. }
  269. }
  270. const bufferView = parameters.bufferView;
  271. const buffer = new draco.DecoderBuffer();
  272. buffer.Init(parameters.array, bufferView.byteLength);
  273. const geometryType = dracoDecoder.GetEncodedGeometryType(buffer);
  274. if (geometryType !== draco.TRIANGULAR_MESH) {
  275. throw new RuntimeError.RuntimeError("Unsupported draco mesh geometry type.");
  276. }
  277. const dracoGeometry = new draco.Mesh();
  278. const decodingStatus = dracoDecoder.DecodeBufferToMesh(buffer, dracoGeometry);
  279. if (!decodingStatus.ok() || dracoGeometry.ptr === 0) {
  280. throw new RuntimeError.RuntimeError(
  281. `Error decoding draco mesh geometry: ${decodingStatus.error_msg()}`
  282. );
  283. }
  284. draco.destroy(buffer);
  285. const attributeData = {};
  286. const compressedAttributes = parameters.compressedAttributes;
  287. for (const attributeName in compressedAttributes) {
  288. if (compressedAttributes.hasOwnProperty(attributeName)) {
  289. const compressedAttribute = compressedAttributes[attributeName];
  290. const dracoAttribute = dracoDecoder.GetAttributeByUniqueId(
  291. dracoGeometry,
  292. compressedAttribute
  293. );
  294. attributeData[attributeName] = decodeAttribute(
  295. dracoGeometry,
  296. dracoDecoder,
  297. dracoAttribute
  298. );
  299. }
  300. }
  301. const result = {
  302. indexArray: decodeIndexArray(dracoGeometry, dracoDecoder),
  303. attributeData: attributeData,
  304. };
  305. draco.destroy(dracoGeometry);
  306. draco.destroy(dracoDecoder);
  307. return result;
  308. }
  309. function decode(parameters) {
  310. if (defaultValue.defined(parameters.bufferView)) {
  311. return decodePrimitive(parameters);
  312. }
  313. return decodePointCloud(parameters);
  314. }
  315. function initWorker(dracoModule) {
  316. draco = dracoModule;
  317. self.onmessage = createTaskProcessorWorker(decode);
  318. self.postMessage(true);
  319. }
  320. function decodeDraco(event) {
  321. const data = event.data;
  322. // Expect the first message to be to load a web assembly module
  323. const wasmConfig = data.webAssemblyConfig;
  324. if (defaultValue.defined(wasmConfig)) {
  325. // Require and compile WebAssembly module, or use fallback if not supported
  326. return require([wasmConfig.modulePath], function (dracoModule) {
  327. if (defaultValue.defined(wasmConfig.wasmBinaryFile)) {
  328. if (!defaultValue.defined(dracoModule)) {
  329. dracoModule = self.DracoDecoderModule;
  330. }
  331. dracoModule(wasmConfig).then(function (compiledModule) {
  332. initWorker(compiledModule);
  333. });
  334. } else {
  335. initWorker(dracoModule());
  336. }
  337. });
  338. }
  339. }
  340. return decodeDraco;
  341. }));