decodeDraco.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /**
  2. * Cesium - https://github.com/CesiumGS/cesium
  3. *
  4. * Copyright 2011-2020 Cesium Contributors
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * Columbus View (Pat. Pend.)
  19. *
  20. * Portions licensed separately.
  21. * See https://github.com/CesiumGS/cesium/blob/master/LICENSE.md for full licensing details.
  22. */
  23. define(['./when-8d13db60', './Check-70bec281', './Math-61ede240', './createTaskProcessorWorker', './RuntimeError-ba10bc3e', './WebGLConstants-4c11ee5f', './ComponentDatatype-5862616f', './IndexDatatype-9435b55f'], function (when, Check, _Math, createTaskProcessorWorker, RuntimeError, WebGLConstants, ComponentDatatype, IndexDatatype) { 'use strict';
  24. /* global require */
  25. var draco;
  26. function decodeIndexArray(dracoGeometry, dracoDecoder) {
  27. var numPoints = dracoGeometry.num_points();
  28. var numFaces = dracoGeometry.num_faces();
  29. var faceIndices = new draco.DracoInt32Array();
  30. var numIndices = numFaces * 3;
  31. var indexArray = IndexDatatype.IndexDatatype.createTypedArray(numPoints, numIndices);
  32. var offset = 0;
  33. for (var i = 0; i < numFaces; ++i) {
  34. dracoDecoder.GetFaceFromMesh(dracoGeometry, i, faceIndices);
  35. indexArray[offset + 0] = faceIndices.GetValue(0);
  36. indexArray[offset + 1] = faceIndices.GetValue(1);
  37. indexArray[offset + 2] = faceIndices.GetValue(2);
  38. offset += 3;
  39. }
  40. draco.destroy(faceIndices);
  41. return {
  42. typedArray : indexArray,
  43. numberOfIndices : numIndices
  44. };
  45. }
  46. function decodeQuantizedDracoTypedArray(dracoGeometry, dracoDecoder, dracoAttribute, quantization, vertexArrayLength) {
  47. var vertexArray;
  48. var attributeData;
  49. if (quantization.quantizationBits <= 8) {
  50. attributeData = new draco.DracoUInt8Array();
  51. vertexArray = new Uint8Array(vertexArrayLength);
  52. dracoDecoder.GetAttributeUInt8ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  53. } else {
  54. attributeData = new draco.DracoUInt16Array();
  55. vertexArray = new Uint16Array(vertexArrayLength);
  56. dracoDecoder.GetAttributeUInt16ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  57. }
  58. for (var i = 0; i < vertexArrayLength; ++i) {
  59. vertexArray[i] = attributeData.GetValue(i);
  60. }
  61. draco.destroy(attributeData);
  62. return vertexArray;
  63. }
  64. function decodeDracoTypedArray(dracoGeometry, dracoDecoder, dracoAttribute, vertexArrayLength) {
  65. var vertexArray;
  66. var attributeData;
  67. // Some attribute types are casted down to 32 bit since Draco only returns 32 bit values
  68. switch (dracoAttribute.data_type()) {
  69. case 1: case 11: // DT_INT8 or DT_BOOL
  70. attributeData = new draco.DracoInt8Array();
  71. vertexArray = new Int8Array(vertexArrayLength);
  72. dracoDecoder.GetAttributeInt8ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  73. break;
  74. case 2: // DT_UINT8
  75. attributeData = new draco.DracoUInt8Array();
  76. vertexArray = new Uint8Array(vertexArrayLength);
  77. dracoDecoder.GetAttributeUInt8ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  78. break;
  79. case 3: // DT_INT16
  80. attributeData = new draco.DracoInt16Array();
  81. vertexArray = new Int16Array(vertexArrayLength);
  82. dracoDecoder.GetAttributeInt16ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  83. break;
  84. case 4: // DT_UINT16
  85. attributeData = new draco.DracoUInt16Array();
  86. vertexArray = new Uint16Array(vertexArrayLength);
  87. dracoDecoder.GetAttributeUInt16ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  88. break;
  89. case 5: case 7: // DT_INT32 or DT_INT64
  90. attributeData = new draco.DracoInt32Array();
  91. vertexArray = new Int32Array(vertexArrayLength);
  92. dracoDecoder.GetAttributeInt32ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  93. break;
  94. case 6: case 8: // DT_UINT32 or DT_UINT64
  95. attributeData = new draco.DracoUInt32Array();
  96. vertexArray = new Uint32Array(vertexArrayLength);
  97. dracoDecoder.GetAttributeUInt32ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  98. break;
  99. case 9: case 10: // DT_FLOAT32 or DT_FLOAT64
  100. attributeData = new draco.DracoFloat32Array();
  101. vertexArray = new Float32Array(vertexArrayLength);
  102. dracoDecoder.GetAttributeFloatForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  103. break;
  104. }
  105. for (var i = 0; i < vertexArrayLength; ++i) {
  106. vertexArray[i] = attributeData.GetValue(i);
  107. }
  108. draco.destroy(attributeData);
  109. return vertexArray;
  110. }
  111. function decodeAttribute(dracoGeometry, dracoDecoder, dracoAttribute) {
  112. var numPoints = dracoGeometry.num_points();
  113. var numComponents = dracoAttribute.num_components();
  114. var quantization;
  115. var transform = new draco.AttributeQuantizationTransform();
  116. if (transform.InitFromAttribute(dracoAttribute)) {
  117. var minValues = new Array(numComponents);
  118. for (var i = 0; i < numComponents; ++i) {
  119. minValues[i] = transform.min_value(i);
  120. }
  121. quantization = {
  122. quantizationBits : transform.quantization_bits(),
  123. minValues : minValues,
  124. range : transform.range(),
  125. octEncoded : false
  126. };
  127. }
  128. draco.destroy(transform);
  129. transform = new draco.AttributeOctahedronTransform();
  130. if (transform.InitFromAttribute(dracoAttribute)) {
  131. quantization = {
  132. quantizationBits : transform.quantization_bits(),
  133. octEncoded : true
  134. };
  135. }
  136. draco.destroy(transform);
  137. var vertexArrayLength = numPoints * numComponents;
  138. var vertexArray;
  139. if (when.defined(quantization)) {
  140. vertexArray = decodeQuantizedDracoTypedArray(dracoGeometry, dracoDecoder, dracoAttribute, quantization, vertexArrayLength);
  141. } else {
  142. vertexArray = decodeDracoTypedArray(dracoGeometry, dracoDecoder, dracoAttribute, vertexArrayLength);
  143. }
  144. var componentDatatype = ComponentDatatype.ComponentDatatype.fromTypedArray(vertexArray);
  145. return {
  146. array : vertexArray,
  147. data : {
  148. componentsPerAttribute : numComponents,
  149. componentDatatype : componentDatatype,
  150. byteOffset : dracoAttribute.byte_offset(),
  151. byteStride : ComponentDatatype.ComponentDatatype.getSizeInBytes(componentDatatype) * numComponents,
  152. normalized : dracoAttribute.normalized(),
  153. quantization : quantization
  154. }
  155. };
  156. }
  157. function decodePointCloud(parameters) {
  158. var dracoDecoder = new draco.Decoder();
  159. if (parameters.dequantizeInShader) {
  160. dracoDecoder.SkipAttributeTransform(draco.POSITION);
  161. dracoDecoder.SkipAttributeTransform(draco.NORMAL);
  162. }
  163. var buffer = new draco.DecoderBuffer();
  164. buffer.Init(parameters.buffer, parameters.buffer.length);
  165. var geometryType = dracoDecoder.GetEncodedGeometryType(buffer);
  166. if (geometryType !== draco.POINT_CLOUD) {
  167. throw new RuntimeError.RuntimeError('Draco geometry type must be POINT_CLOUD.');
  168. }
  169. var dracoPointCloud = new draco.PointCloud();
  170. var decodingStatus = dracoDecoder.DecodeBufferToPointCloud(buffer, dracoPointCloud);
  171. if (!decodingStatus.ok() || dracoPointCloud.ptr === 0) {
  172. throw new RuntimeError.RuntimeError('Error decoding draco point cloud: ' + decodingStatus.error_msg());
  173. }
  174. draco.destroy(buffer);
  175. var result = {};
  176. var properties = parameters.properties;
  177. for (var propertyName in properties) {
  178. if (properties.hasOwnProperty(propertyName)) {
  179. var attributeId = properties[propertyName];
  180. var dracoAttribute = dracoDecoder.GetAttributeByUniqueId(dracoPointCloud, attributeId);
  181. result[propertyName] = decodeAttribute(dracoPointCloud, dracoDecoder, dracoAttribute);
  182. }
  183. }
  184. draco.destroy(dracoPointCloud);
  185. draco.destroy(dracoDecoder);
  186. return result;
  187. }
  188. function decodePrimitive(parameters) {
  189. var dracoDecoder = new draco.Decoder();
  190. // Skip all parameter types except generic
  191. var attributesToSkip = ['POSITION', 'NORMAL', 'COLOR', 'TEX_COORD'];
  192. if (parameters.dequantizeInShader) {
  193. for (var i = 0; i < attributesToSkip.length; ++i) {
  194. dracoDecoder.SkipAttributeTransform(draco[attributesToSkip[i]]);
  195. }
  196. }
  197. var bufferView = parameters.bufferView;
  198. var buffer = new draco.DecoderBuffer();
  199. buffer.Init(parameters.array, bufferView.byteLength);
  200. var geometryType = dracoDecoder.GetEncodedGeometryType(buffer);
  201. if (geometryType !== draco.TRIANGULAR_MESH) {
  202. throw new RuntimeError.RuntimeError('Unsupported draco mesh geometry type.');
  203. }
  204. var dracoGeometry = new draco.Mesh();
  205. var decodingStatus = dracoDecoder.DecodeBufferToMesh(buffer, dracoGeometry);
  206. if (!decodingStatus.ok() || dracoGeometry.ptr === 0) {
  207. throw new RuntimeError.RuntimeError('Error decoding draco mesh geometry: ' + decodingStatus.error_msg());
  208. }
  209. draco.destroy(buffer);
  210. var attributeData = {};
  211. var compressedAttributes = parameters.compressedAttributes;
  212. for (var attributeName in compressedAttributes) {
  213. if (compressedAttributes.hasOwnProperty(attributeName)) {
  214. var compressedAttribute = compressedAttributes[attributeName];
  215. var dracoAttribute = dracoDecoder.GetAttributeByUniqueId(dracoGeometry, compressedAttribute);
  216. attributeData[attributeName] = decodeAttribute(dracoGeometry, dracoDecoder, dracoAttribute);
  217. }
  218. }
  219. var result = {
  220. indexArray : decodeIndexArray(dracoGeometry, dracoDecoder),
  221. attributeData : attributeData
  222. };
  223. draco.destroy(dracoGeometry);
  224. draco.destroy(dracoDecoder);
  225. return result;
  226. }
  227. function decode(parameters) {
  228. if (when.defined(parameters.primitive)) {
  229. return decodePrimitive(parameters);
  230. }
  231. return decodePointCloud(parameters);
  232. }
  233. function initWorker(dracoModule) {
  234. draco = dracoModule;
  235. self.onmessage = createTaskProcessorWorker(decode);
  236. self.postMessage(true);
  237. }
  238. function decodeDraco(event) {
  239. var data = event.data;
  240. // Expect the first message to be to load a web assembly module
  241. var wasmConfig = data.webAssemblyConfig;
  242. if (when.defined(wasmConfig)) {
  243. // Require and compile WebAssembly module, or use fallback if not supported
  244. return require([wasmConfig.modulePath], function(dracoModule) {
  245. if (when.defined(wasmConfig.wasmBinaryFile)) {
  246. if (!when.defined(dracoModule)) {
  247. dracoModule = self.DracoDecoderModule;
  248. }
  249. dracoModule(wasmConfig).then(function (compiledModule) {
  250. initWorker(compiledModule);
  251. });
  252. } else {
  253. initWorker(dracoModule());
  254. }
  255. });
  256. }
  257. }
  258. return decodeDraco;
  259. });