decodeDraco.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /* global require */
  2. import ComponentDatatype from '../Core/ComponentDatatype.js';
  3. import defined from '../Core/defined.js';
  4. import IndexDatatype from '../Core/IndexDatatype.js';
  5. import RuntimeError from '../Core/RuntimeError.js';
  6. import createTaskProcessorWorker from './createTaskProcessorWorker.js';
  7. var draco;
  8. function decodeIndexArray(dracoGeometry, dracoDecoder) {
  9. var numPoints = dracoGeometry.num_points();
  10. var numFaces = dracoGeometry.num_faces();
  11. var faceIndices = new draco.DracoInt32Array();
  12. var numIndices = numFaces * 3;
  13. var indexArray = IndexDatatype.createTypedArray(numPoints, numIndices);
  14. var offset = 0;
  15. for (var i = 0; i < numFaces; ++i) {
  16. dracoDecoder.GetFaceFromMesh(dracoGeometry, i, faceIndices);
  17. indexArray[offset + 0] = faceIndices.GetValue(0);
  18. indexArray[offset + 1] = faceIndices.GetValue(1);
  19. indexArray[offset + 2] = faceIndices.GetValue(2);
  20. offset += 3;
  21. }
  22. draco.destroy(faceIndices);
  23. return {
  24. typedArray : indexArray,
  25. numberOfIndices : numIndices
  26. };
  27. }
  28. function decodeQuantizedDracoTypedArray(dracoGeometry, dracoDecoder, dracoAttribute, quantization, vertexArrayLength) {
  29. var vertexArray;
  30. var attributeData;
  31. if (quantization.quantizationBits <= 8) {
  32. attributeData = new draco.DracoUInt8Array();
  33. vertexArray = new Uint8Array(vertexArrayLength);
  34. dracoDecoder.GetAttributeUInt8ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  35. } else {
  36. attributeData = new draco.DracoUInt16Array();
  37. vertexArray = new Uint16Array(vertexArrayLength);
  38. dracoDecoder.GetAttributeUInt16ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  39. }
  40. for (var i = 0; i < vertexArrayLength; ++i) {
  41. vertexArray[i] = attributeData.GetValue(i);
  42. }
  43. draco.destroy(attributeData);
  44. return vertexArray;
  45. }
  46. function decodeDracoTypedArray(dracoGeometry, dracoDecoder, dracoAttribute, vertexArrayLength) {
  47. var vertexArray;
  48. var attributeData;
  49. // Some attribute types are casted down to 32 bit since Draco only returns 32 bit values
  50. switch (dracoAttribute.data_type()) {
  51. case 1: case 11: // DT_INT8 or DT_BOOL
  52. attributeData = new draco.DracoInt8Array();
  53. vertexArray = new Int8Array(vertexArrayLength);
  54. dracoDecoder.GetAttributeInt8ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  55. break;
  56. case 2: // DT_UINT8
  57. attributeData = new draco.DracoUInt8Array();
  58. vertexArray = new Uint8Array(vertexArrayLength);
  59. dracoDecoder.GetAttributeUInt8ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  60. break;
  61. case 3: // DT_INT16
  62. attributeData = new draco.DracoInt16Array();
  63. vertexArray = new Int16Array(vertexArrayLength);
  64. dracoDecoder.GetAttributeInt16ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  65. break;
  66. case 4: // DT_UINT16
  67. attributeData = new draco.DracoUInt16Array();
  68. vertexArray = new Uint16Array(vertexArrayLength);
  69. dracoDecoder.GetAttributeUInt16ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  70. break;
  71. case 5: case 7: // DT_INT32 or DT_INT64
  72. attributeData = new draco.DracoInt32Array();
  73. vertexArray = new Int32Array(vertexArrayLength);
  74. dracoDecoder.GetAttributeInt32ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  75. break;
  76. case 6: case 8: // DT_UINT32 or DT_UINT64
  77. attributeData = new draco.DracoUInt32Array();
  78. vertexArray = new Uint32Array(vertexArrayLength);
  79. dracoDecoder.GetAttributeUInt32ForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  80. break;
  81. case 9: case 10: // DT_FLOAT32 or DT_FLOAT64
  82. attributeData = new draco.DracoFloat32Array();
  83. vertexArray = new Float32Array(vertexArrayLength);
  84. dracoDecoder.GetAttributeFloatForAllPoints(dracoGeometry, dracoAttribute, attributeData);
  85. break;
  86. }
  87. for (var i = 0; i < vertexArrayLength; ++i) {
  88. vertexArray[i] = attributeData.GetValue(i);
  89. }
  90. draco.destroy(attributeData);
  91. return vertexArray;
  92. }
  93. function decodeAttribute(dracoGeometry, dracoDecoder, dracoAttribute) {
  94. var numPoints = dracoGeometry.num_points();
  95. var numComponents = dracoAttribute.num_components();
  96. var quantization;
  97. var transform = new draco.AttributeQuantizationTransform();
  98. if (transform.InitFromAttribute(dracoAttribute)) {
  99. var minValues = new Array(numComponents);
  100. for (var i = 0; i < numComponents; ++i) {
  101. minValues[i] = transform.min_value(i);
  102. }
  103. quantization = {
  104. quantizationBits : transform.quantization_bits(),
  105. minValues : minValues,
  106. range : transform.range(),
  107. octEncoded : false
  108. };
  109. }
  110. draco.destroy(transform);
  111. transform = new draco.AttributeOctahedronTransform();
  112. if (transform.InitFromAttribute(dracoAttribute)) {
  113. quantization = {
  114. quantizationBits : transform.quantization_bits(),
  115. octEncoded : true
  116. };
  117. }
  118. draco.destroy(transform);
  119. var vertexArrayLength = numPoints * numComponents;
  120. var vertexArray;
  121. if (defined(quantization)) {
  122. vertexArray = decodeQuantizedDracoTypedArray(dracoGeometry, dracoDecoder, dracoAttribute, quantization, vertexArrayLength);
  123. } else {
  124. vertexArray = decodeDracoTypedArray(dracoGeometry, dracoDecoder, dracoAttribute, vertexArrayLength);
  125. }
  126. var componentDatatype = ComponentDatatype.fromTypedArray(vertexArray);
  127. return {
  128. array : vertexArray,
  129. data : {
  130. componentsPerAttribute : numComponents,
  131. componentDatatype : componentDatatype,
  132. byteOffset : dracoAttribute.byte_offset(),
  133. byteStride : ComponentDatatype.getSizeInBytes(componentDatatype) * numComponents,
  134. normalized : dracoAttribute.normalized(),
  135. quantization : quantization
  136. }
  137. };
  138. }
  139. function decodePointCloud(parameters) {
  140. var dracoDecoder = new draco.Decoder();
  141. if (parameters.dequantizeInShader) {
  142. dracoDecoder.SkipAttributeTransform(draco.POSITION);
  143. dracoDecoder.SkipAttributeTransform(draco.NORMAL);
  144. }
  145. var buffer = new draco.DecoderBuffer();
  146. buffer.Init(parameters.buffer, parameters.buffer.length);
  147. var geometryType = dracoDecoder.GetEncodedGeometryType(buffer);
  148. if (geometryType !== draco.POINT_CLOUD) {
  149. throw new RuntimeError('Draco geometry type must be POINT_CLOUD.');
  150. }
  151. var dracoPointCloud = new draco.PointCloud();
  152. var decodingStatus = dracoDecoder.DecodeBufferToPointCloud(buffer, dracoPointCloud);
  153. if (!decodingStatus.ok() || dracoPointCloud.ptr === 0) {
  154. throw new RuntimeError('Error decoding draco point cloud: ' + decodingStatus.error_msg());
  155. }
  156. draco.destroy(buffer);
  157. var result = {};
  158. var properties = parameters.properties;
  159. for (var propertyName in properties) {
  160. if (properties.hasOwnProperty(propertyName)) {
  161. var attributeId = properties[propertyName];
  162. var dracoAttribute = dracoDecoder.GetAttributeByUniqueId(dracoPointCloud, attributeId);
  163. result[propertyName] = decodeAttribute(dracoPointCloud, dracoDecoder, dracoAttribute);
  164. }
  165. }
  166. draco.destroy(dracoPointCloud);
  167. draco.destroy(dracoDecoder);
  168. return result;
  169. }
  170. function decodePrimitive(parameters) {
  171. var dracoDecoder = new draco.Decoder();
  172. // Skip all parameter types except generic
  173. var attributesToSkip = ['POSITION', 'NORMAL', 'COLOR', 'TEX_COORD'];
  174. if (parameters.dequantizeInShader) {
  175. for (var i = 0; i < attributesToSkip.length; ++i) {
  176. dracoDecoder.SkipAttributeTransform(draco[attributesToSkip[i]]);
  177. }
  178. }
  179. var bufferView = parameters.bufferView;
  180. var buffer = new draco.DecoderBuffer();
  181. buffer.Init(parameters.array, bufferView.byteLength);
  182. var geometryType = dracoDecoder.GetEncodedGeometryType(buffer);
  183. if (geometryType !== draco.TRIANGULAR_MESH) {
  184. throw new RuntimeError('Unsupported draco mesh geometry type.');
  185. }
  186. var dracoGeometry = new draco.Mesh();
  187. var decodingStatus = dracoDecoder.DecodeBufferToMesh(buffer, dracoGeometry);
  188. if (!decodingStatus.ok() || dracoGeometry.ptr === 0) {
  189. throw new RuntimeError('Error decoding draco mesh geometry: ' + decodingStatus.error_msg());
  190. }
  191. draco.destroy(buffer);
  192. var attributeData = {};
  193. var compressedAttributes = parameters.compressedAttributes;
  194. for (var attributeName in compressedAttributes) {
  195. if (compressedAttributes.hasOwnProperty(attributeName)) {
  196. var compressedAttribute = compressedAttributes[attributeName];
  197. var dracoAttribute = dracoDecoder.GetAttributeByUniqueId(dracoGeometry, compressedAttribute);
  198. attributeData[attributeName] = decodeAttribute(dracoGeometry, dracoDecoder, dracoAttribute);
  199. }
  200. }
  201. var result = {
  202. indexArray : decodeIndexArray(dracoGeometry, dracoDecoder),
  203. attributeData : attributeData
  204. };
  205. draco.destroy(dracoGeometry);
  206. draco.destroy(dracoDecoder);
  207. return result;
  208. }
  209. function decode(parameters) {
  210. if (defined(parameters.primitive)) {
  211. return decodePrimitive(parameters);
  212. }
  213. return decodePointCloud(parameters);
  214. }
  215. function initWorker(dracoModule) {
  216. draco = dracoModule;
  217. self.onmessage = createTaskProcessorWorker(decode);
  218. self.postMessage(true);
  219. }
  220. function decodeDraco(event) {
  221. var data = event.data;
  222. // Expect the first message to be to load a web assembly module
  223. var wasmConfig = data.webAssemblyConfig;
  224. if (defined(wasmConfig)) {
  225. // Require and compile WebAssembly module, or use fallback if not supported
  226. return require([wasmConfig.modulePath], function(dracoModule) {
  227. if (defined(wasmConfig.wasmBinaryFile)) {
  228. if (!defined(dracoModule)) {
  229. dracoModule = self.DracoDecoderModule;
  230. }
  231. dracoModule(wasmConfig).then(function (compiledModule) {
  232. initWorker(compiledModule);
  233. });
  234. } else {
  235. initWorker(dracoModule());
  236. }
  237. });
  238. }
  239. }
  240. export default decodeDraco;