@loaders.gl/tile-converter 3.2.12 → 3.3.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/dist/3d-tiles-attributes-worker.d.ts +3 -3
  2. package/dist/3d-tiles-attributes-worker.d.ts.map +1 -1
  3. package/dist/3d-tiles-attributes-worker.js +2 -3
  4. package/dist/3d-tiles-attributes-worker.js.map +3 -3
  5. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts +8 -0
  6. package/dist/3d-tiles-converter/3d-tiles-converter.d.ts.map +1 -1
  7. package/dist/3d-tiles-converter/3d-tiles-converter.js +57 -43
  8. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts +5 -5
  9. package/dist/3d-tiles-converter/helpers/b3dm-converter.d.ts.map +1 -1
  10. package/dist/3d-tiles-converter/helpers/b3dm-converter.js +21 -17
  11. package/dist/converter-cli.js +43 -8
  12. package/dist/converter.min.js +24 -21
  13. package/dist/deps-installer/deps-installer.d.ts +5 -1
  14. package/dist/deps-installer/deps-installer.d.ts.map +1 -1
  15. package/dist/deps-installer/deps-installer.js +29 -1
  16. package/dist/dist.min.js +58405 -61237
  17. package/dist/es5/3d-tiles-attributes-worker.js +4 -7
  18. package/dist/es5/3d-tiles-attributes-worker.js.map +1 -1
  19. package/dist/es5/3d-tiles-converter/3d-tiles-converter.js +125 -210
  20. package/dist/es5/3d-tiles-converter/3d-tiles-converter.js.map +1 -1
  21. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js +53 -85
  22. package/dist/es5/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  23. package/dist/es5/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js +0 -8
  24. package/dist/es5/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js.map +1 -1
  25. package/dist/es5/3d-tiles-converter/helpers/texture-atlas.js +0 -5
  26. package/dist/es5/3d-tiles-converter/helpers/texture-atlas.js.map +1 -1
  27. package/dist/es5/3d-tiles-converter/json-templates/tileset.js +0 -6
  28. package/dist/es5/3d-tiles-converter/json-templates/tileset.js.map +1 -1
  29. package/dist/es5/bundle.js +0 -1
  30. package/dist/es5/bundle.js.map +1 -1
  31. package/dist/es5/constants.js.map +1 -1
  32. package/dist/es5/converter-cli.js +50 -60
  33. package/dist/es5/converter-cli.js.map +1 -1
  34. package/dist/es5/deps-installer/deps-installer.js +73 -28
  35. package/dist/es5/deps-installer/deps-installer.js.map +1 -1
  36. package/dist/es5/i3s-attributes-worker.js +3 -6
  37. package/dist/es5/i3s-attributes-worker.js.map +1 -1
  38. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js +124 -0
  39. package/dist/es5/i3s-converter/helpers/batch-ids-extensions.js.map +1 -0
  40. package/dist/es5/i3s-converter/helpers/coordinate-converter.js +2 -19
  41. package/dist/es5/i3s-converter/helpers/coordinate-converter.js.map +1 -1
  42. package/dist/es5/i3s-converter/helpers/create-scene-server-path.js +0 -11
  43. package/dist/es5/i3s-converter/helpers/create-scene-server-path.js.map +1 -1
  44. package/dist/es5/i3s-converter/helpers/feature-attributes.js +184 -0
  45. package/dist/es5/i3s-converter/helpers/feature-attributes.js.map +1 -0
  46. package/dist/es5/i3s-converter/helpers/geometry-attributes.js +60 -51
  47. package/dist/es5/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  48. package/dist/es5/i3s-converter/helpers/geometry-converter.js +516 -356
  49. package/dist/es5/i3s-converter/helpers/geometry-converter.js.map +1 -1
  50. package/dist/es5/i3s-converter/helpers/gltf-attributes.js +57 -43
  51. package/dist/es5/i3s-converter/helpers/gltf-attributes.js.map +1 -1
  52. package/dist/es5/i3s-converter/helpers/node-debug.js +4 -23
  53. package/dist/es5/i3s-converter/helpers/node-debug.js.map +1 -1
  54. package/dist/es5/i3s-converter/helpers/node-index-document.js +507 -0
  55. package/dist/es5/i3s-converter/helpers/node-index-document.js.map +1 -0
  56. package/dist/es5/i3s-converter/helpers/node-pages.js +462 -208
  57. package/dist/es5/i3s-converter/helpers/node-pages.js.map +1 -1
  58. package/dist/es5/i3s-converter/i3s-converter.js +722 -1153
  59. package/dist/es5/i3s-converter/i3s-converter.js.map +1 -1
  60. package/dist/es5/i3s-converter/json-templates/geometry-definitions.js +107 -0
  61. package/dist/es5/i3s-converter/json-templates/geometry-definitions.js.map +1 -0
  62. package/dist/es5/i3s-converter/json-templates/layers.js +2 -107
  63. package/dist/es5/i3s-converter/json-templates/layers.js.map +1 -1
  64. package/dist/es5/i3s-converter/json-templates/metadata.js +0 -2
  65. package/dist/es5/i3s-converter/json-templates/metadata.js.map +1 -1
  66. package/dist/es5/i3s-converter/json-templates/node.js +2 -12
  67. package/dist/es5/i3s-converter/json-templates/node.js.map +1 -1
  68. package/dist/es5/i3s-converter/json-templates/scene-server.js +0 -2
  69. package/dist/es5/i3s-converter/json-templates/scene-server.js.map +1 -1
  70. package/dist/es5/i3s-converter/json-templates/shared-resources.js +9 -32
  71. package/dist/es5/i3s-converter/json-templates/shared-resources.js.map +1 -1
  72. package/dist/es5/i3s-converter/json-templates/store.js.map +1 -1
  73. package/dist/es5/i3s-converter/types.js.map +1 -1
  74. package/dist/es5/i3s-server/app.js +0 -5
  75. package/dist/es5/i3s-server/app.js.map +1 -1
  76. package/dist/es5/i3s-server/controllers/index-controller.js +0 -16
  77. package/dist/es5/i3s-server/controllers/index-controller.js.map +1 -1
  78. package/dist/es5/i3s-server/routes/index.js +1 -10
  79. package/dist/es5/i3s-server/routes/index.js.map +1 -1
  80. package/dist/es5/index.js +0 -3
  81. package/dist/es5/index.js.map +1 -1
  82. package/dist/es5/lib/utils/compress-util.js +19 -74
  83. package/dist/es5/lib/utils/compress-util.js.map +1 -1
  84. package/dist/es5/lib/utils/file-utils.js +103 -47
  85. package/dist/es5/lib/utils/file-utils.js.map +1 -1
  86. package/dist/es5/lib/utils/lod-conversion-utils.js +0 -7
  87. package/dist/es5/lib/utils/lod-conversion-utils.js.map +1 -1
  88. package/dist/es5/lib/utils/queue.js +0 -14
  89. package/dist/es5/lib/utils/queue.js.map +1 -1
  90. package/dist/es5/lib/utils/statistic-utills.js +1 -46
  91. package/dist/es5/lib/utils/statistic-utills.js.map +1 -1
  92. package/dist/es5/lib/utils/write-queue.js +41 -82
  93. package/dist/es5/lib/utils/write-queue.js.map +1 -1
  94. package/dist/es5/pgm-loader.js +1 -8
  95. package/dist/es5/pgm-loader.js.map +1 -1
  96. package/dist/es5/workers/3d-tiles-attributes-worker.js +2 -9
  97. package/dist/es5/workers/3d-tiles-attributes-worker.js.map +1 -1
  98. package/dist/es5/workers/i3s-attributes-worker.js +2 -10
  99. package/dist/es5/workers/i3s-attributes-worker.js.map +1 -1
  100. package/dist/esm/3d-tiles-attributes-worker.js +4 -2
  101. package/dist/esm/3d-tiles-attributes-worker.js.map +1 -1
  102. package/dist/esm/3d-tiles-converter/3d-tiles-converter.js +60 -77
  103. package/dist/esm/3d-tiles-converter/3d-tiles-converter.js.map +1 -1
  104. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js +29 -50
  105. package/dist/esm/3d-tiles-converter/helpers/b3dm-converter.js.map +1 -1
  106. package/dist/esm/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js +1 -0
  107. package/dist/esm/3d-tiles-converter/helpers/i3s-obb-to-3d-tiles-obb.js.map +1 -1
  108. package/dist/esm/3d-tiles-converter/helpers/texture-atlas.js +1 -4
  109. package/dist/esm/3d-tiles-converter/helpers/texture-atlas.js.map +1 -1
  110. package/dist/esm/3d-tiles-converter/json-templates/tileset.js +0 -3
  111. package/dist/esm/3d-tiles-converter/json-templates/tileset.js.map +1 -1
  112. package/dist/esm/bundle.js +1 -1
  113. package/dist/esm/bundle.js.map +1 -1
  114. package/dist/esm/constants.js.map +1 -1
  115. package/dist/esm/converter-cli.js +46 -40
  116. package/dist/esm/converter-cli.js.map +1 -1
  117. package/dist/esm/deps-installer/deps-installer.js +30 -4
  118. package/dist/esm/deps-installer/deps-installer.js.map +1 -1
  119. package/dist/esm/i3s-attributes-worker.js +3 -1
  120. package/dist/esm/i3s-attributes-worker.js.map +1 -1
  121. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js +113 -0
  122. package/dist/esm/i3s-converter/helpers/batch-ids-extensions.js.map +1 -0
  123. package/dist/esm/i3s-converter/helpers/coordinate-converter.js +5 -6
  124. package/dist/esm/i3s-converter/helpers/coordinate-converter.js.map +1 -1
  125. package/dist/esm/i3s-converter/helpers/create-scene-server-path.js +1 -0
  126. package/dist/esm/i3s-converter/helpers/create-scene-server-path.js.map +1 -1
  127. package/dist/esm/i3s-converter/helpers/feature-attributes.js +158 -0
  128. package/dist/esm/i3s-converter/helpers/feature-attributes.js.map +1 -0
  129. package/dist/esm/i3s-converter/helpers/geometry-attributes.js +39 -33
  130. package/dist/esm/i3s-converter/helpers/geometry-attributes.js.map +1 -1
  131. package/dist/esm/i3s-converter/helpers/geometry-converter.js +295 -196
  132. package/dist/esm/i3s-converter/helpers/geometry-converter.js.map +1 -1
  133. package/dist/esm/i3s-converter/helpers/gltf-attributes.js +59 -34
  134. package/dist/esm/i3s-converter/helpers/gltf-attributes.js.map +1 -1
  135. package/dist/esm/i3s-converter/helpers/node-debug.js +3 -13
  136. package/dist/esm/i3s-converter/helpers/node-debug.js.map +1 -1
  137. package/dist/esm/i3s-converter/helpers/node-index-document.js +197 -0
  138. package/dist/esm/i3s-converter/helpers/node-index-document.js.map +1 -0
  139. package/dist/esm/i3s-converter/helpers/node-pages.js +161 -87
  140. package/dist/esm/i3s-converter/helpers/node-pages.js.map +1 -1
  141. package/dist/esm/i3s-converter/i3s-converter.js +216 -491
  142. package/dist/esm/i3s-converter/i3s-converter.js.map +1 -1
  143. package/dist/esm/i3s-converter/json-templates/geometry-definitions.js +89 -0
  144. package/dist/esm/i3s-converter/json-templates/geometry-definitions.js.map +1 -0
  145. package/dist/esm/i3s-converter/json-templates/layers.js +2 -95
  146. package/dist/esm/i3s-converter/json-templates/layers.js.map +1 -1
  147. package/dist/esm/i3s-converter/json-templates/metadata.js.map +1 -1
  148. package/dist/esm/i3s-converter/json-templates/node.js +0 -4
  149. package/dist/esm/i3s-converter/json-templates/node.js.map +1 -1
  150. package/dist/esm/i3s-converter/json-templates/scene-server.js.map +1 -1
  151. package/dist/esm/i3s-converter/json-templates/shared-resources.js +3 -15
  152. package/dist/esm/i3s-converter/json-templates/shared-resources.js.map +1 -1
  153. package/dist/esm/i3s-converter/json-templates/store.js.map +1 -1
  154. package/dist/esm/i3s-converter/types.js.map +1 -1
  155. package/dist/esm/i3s-server/app.js +0 -5
  156. package/dist/esm/i3s-server/app.js.map +1 -1
  157. package/dist/esm/i3s-server/controllers/index-controller.js +0 -5
  158. package/dist/esm/i3s-server/controllers/index-controller.js.map +1 -1
  159. package/dist/esm/i3s-server/routes/index.js +0 -3
  160. package/dist/esm/i3s-server/routes/index.js.map +1 -1
  161. package/dist/esm/index.js.map +1 -1
  162. package/dist/esm/lib/utils/compress-util.js +19 -12
  163. package/dist/esm/lib/utils/compress-util.js.map +1 -1
  164. package/dist/esm/lib/utils/file-utils.js +54 -11
  165. package/dist/esm/lib/utils/file-utils.js.map +1 -1
  166. package/dist/esm/lib/utils/lod-conversion-utils.js +2 -6
  167. package/dist/esm/lib/utils/lod-conversion-utils.js.map +1 -1
  168. package/dist/esm/lib/utils/queue.js +0 -4
  169. package/dist/esm/lib/utils/queue.js.map +1 -1
  170. package/dist/esm/lib/utils/statistic-utills.js +0 -11
  171. package/dist/esm/lib/utils/statistic-utills.js.map +1 -1
  172. package/dist/esm/lib/utils/write-queue.js +27 -38
  173. package/dist/esm/lib/utils/write-queue.js.map +1 -1
  174. package/dist/esm/pgm-loader.js +3 -1
  175. package/dist/esm/pgm-loader.js.map +1 -1
  176. package/dist/esm/workers/3d-tiles-attributes-worker.js +4 -1
  177. package/dist/esm/workers/3d-tiles-attributes-worker.js.map +1 -1
  178. package/dist/esm/workers/i3s-attributes-worker.js +4 -1
  179. package/dist/esm/workers/i3s-attributes-worker.js.map +1 -1
  180. package/dist/i3s-attributes-worker.d.ts +7 -3
  181. package/dist/i3s-attributes-worker.d.ts.map +1 -1
  182. package/dist/i3s-attributes-worker.js +2 -3
  183. package/dist/i3s-attributes-worker.js.map +3 -3
  184. package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts +11 -0
  185. package/dist/i3s-converter/helpers/batch-ids-extensions.d.ts.map +1 -0
  186. package/dist/i3s-converter/helpers/batch-ids-extensions.js +141 -0
  187. package/dist/i3s-converter/helpers/coordinate-converter.d.ts +2 -2
  188. package/dist/i3s-converter/helpers/coordinate-converter.d.ts.map +1 -1
  189. package/dist/i3s-converter/helpers/feature-attributes.d.ts +56 -0
  190. package/dist/i3s-converter/helpers/feature-attributes.d.ts.map +1 -0
  191. package/dist/i3s-converter/helpers/feature-attributes.js +216 -0
  192. package/dist/i3s-converter/helpers/geometry-attributes.d.ts.map +1 -1
  193. package/dist/i3s-converter/helpers/geometry-attributes.js +42 -17
  194. package/dist/i3s-converter/helpers/geometry-converter.d.ts +18 -6
  195. package/dist/i3s-converter/helpers/geometry-converter.d.ts.map +1 -1
  196. package/dist/i3s-converter/helpers/geometry-converter.js +349 -99
  197. package/dist/i3s-converter/helpers/gltf-attributes.d.ts.map +1 -1
  198. package/dist/i3s-converter/helpers/gltf-attributes.js +53 -21
  199. package/dist/i3s-converter/helpers/node-index-document.d.ts +91 -0
  200. package/dist/i3s-converter/helpers/node-index-document.d.ts.map +1 -0
  201. package/dist/i3s-converter/helpers/node-index-document.js +242 -0
  202. package/dist/i3s-converter/helpers/node-pages.d.ts +81 -42
  203. package/dist/i3s-converter/helpers/node-pages.d.ts.map +1 -1
  204. package/dist/i3s-converter/helpers/node-pages.js +200 -92
  205. package/dist/i3s-converter/i3s-converter.d.ts +52 -108
  206. package/dist/i3s-converter/i3s-converter.d.ts.map +1 -1
  207. package/dist/i3s-converter/i3s-converter.js +218 -403
  208. package/dist/i3s-converter/json-templates/geometry-definitions.d.ts +7 -0
  209. package/dist/i3s-converter/json-templates/geometry-definitions.d.ts.map +1 -0
  210. package/dist/i3s-converter/json-templates/geometry-definitions.js +87 -0
  211. package/dist/i3s-converter/json-templates/layers.d.ts +1 -30
  212. package/dist/i3s-converter/json-templates/layers.d.ts.map +1 -1
  213. package/dist/i3s-converter/json-templates/layers.js +2 -86
  214. package/dist/i3s-converter/json-templates/shared-resources.js +3 -3
  215. package/dist/i3s-converter/types.d.ts +38 -8
  216. package/dist/i3s-converter/types.d.ts.map +1 -1
  217. package/dist/lib/utils/file-utils.d.ts +17 -1
  218. package/dist/lib/utils/file-utils.d.ts.map +1 -1
  219. package/dist/lib/utils/file-utils.js +64 -7
  220. package/dist/lib/utils/write-queue.d.ts +19 -3
  221. package/dist/lib/utils/write-queue.d.ts.map +1 -1
  222. package/dist/lib/utils/write-queue.js +21 -16
  223. package/dist/pgm-loader.d.ts.map +1 -1
  224. package/dist/pgm-loader.js +2 -1
  225. package/dist/workers/3d-tiles-attributes-worker.js +1 -1
  226. package/dist/workers/i3s-attributes-worker.js +1 -1
  227. package/package.json +18 -16
  228. package/src/3d-tiles-attributes-worker.ts +1 -1
  229. package/src/3d-tiles-converter/3d-tiles-converter.ts +71 -55
  230. package/src/3d-tiles-converter/helpers/b3dm-converter.ts +25 -18
  231. package/src/converter-cli.ts +54 -8
  232. package/src/deps-installer/deps-installer.ts +38 -2
  233. package/src/i3s-attributes-worker.ts +5 -1
  234. package/src/i3s-converter/helpers/batch-ids-extensions.ts +206 -0
  235. package/src/i3s-converter/helpers/coordinate-converter.ts +2 -2
  236. package/src/i3s-converter/helpers/feature-attributes.ts +247 -0
  237. package/src/i3s-converter/helpers/geometry-attributes.ts +46 -18
  238. package/src/i3s-converter/helpers/geometry-converter.ts +423 -111
  239. package/src/i3s-converter/helpers/gltf-attributes.ts +59 -24
  240. package/src/i3s-converter/helpers/node-index-document.ts +306 -0
  241. package/src/i3s-converter/helpers/node-pages.ts +222 -109
  242. package/src/i3s-converter/i3s-converter.ts +264 -487
  243. package/src/i3s-converter/json-templates/geometry-definitions.ts +83 -0
  244. package/src/i3s-converter/json-templates/layers.ts +2 -91
  245. package/src/i3s-converter/json-templates/shared-resources.ts +3 -3
  246. package/src/i3s-converter/types.ts +33 -2
  247. package/src/lib/utils/file-utils.ts +62 -7
  248. package/src/lib/utils/write-queue.ts +42 -19
  249. package/src/pgm-loader.ts +2 -2
  250. package/src/workers/3d-tiles-attributes-worker.ts +1 -1
  251. package/src/workers/i3s-attributes-worker.ts +2 -1
@@ -1,18 +1,44 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.convertAttributes = void 0;
29
+ exports.getPropertyTable = exports.convertAttributes = void 0;
7
30
  const core_1 = require("@math.gl/core");
8
31
  const geospatial_1 = require("@math.gl/geospatial");
9
32
  const draco_1 = require("@loaders.gl/draco");
10
33
  const core_2 = require("@loaders.gl/core");
11
34
  const loader_utils_1 = require("@loaders.gl/loader-utils");
12
35
  const md5_1 = __importDefault(require("md5"));
36
+ const uuid_1 = require("uuid");
13
37
  const geometry_attributes_1 = require("./geometry-attributes");
14
38
  const coordinate_converter_1 = require("./coordinate-converter");
15
39
  const gltf_attributes_1 = require("./gltf-attributes");
40
+ const batch_ids_extensions_1 = require("./batch-ids-extensions");
41
+ const feature_attributes_1 = require("./feature-attributes");
16
42
  // Spec - https://github.com/Esri/i3s-spec/blob/master/docs/1.7/pbrMetallicRoughness.cmn.md
17
43
  const DEFAULT_ROUGHNESS_FACTOR = 1;
18
44
  const DEFAULT_METALLIC_FACTOR = 1;
@@ -29,68 +55,64 @@ const OBJECT_ID_TYPE = 'Oid32';
29
55
  * BATCHID - Legacy attribute name which includes batch info.
30
56
  */
31
57
  const BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES = ['CUSTOM_ATTRIBUTE_2', '_BATCHID', 'BATCHID'];
58
+ const EXT_FEATURE_METADATA = 'EXT_feature_metadata';
59
+ const EXT_MESH_FEATURES = 'EXT_mesh_features';
32
60
  let scratchVector = new core_1.Vector3();
33
61
  /**
34
62
  * Convert binary data from b3dm file to i3s resources
35
63
  *
36
64
  * @param tileContent - 3d tile content
37
- * @param nodeId - target nodeId. If a few nodes will be created - ids will be nodeId+n where n - index in the resulting array
65
+ * @param addNodeToNodePage - function to add new node to node pages
66
+ * @param propertyTable - batch table (corresponding to feature attributes data)
38
67
  * @param featuresHashArray - hash array of features that is needed to not to mix up same features in parent and child nodes
39
68
  * @param attributeStorageInfo - attributes metadata from 3DSceneLayer json
40
69
  * @param draco - is converter should create draco compressed geometry
41
70
  * @param generateBoundingVolumes - is converter should create accurate bounding voulmes from geometry attributes
71
+ * @param shouldMergeMaterials - Try to merge similar materials to be able to merge meshes into one node
42
72
  * @param geoidHeightModel - model to convert elevation from elipsoidal to geoid
73
+ * @param workerSource - source code of used workers
43
74
  * @returns Array of node resources to create one or more i3s nodes
44
75
  */
45
- async function convertB3dmToI3sGeometry(tileContent, nodeId, featuresHashArray, attributeStorageInfo, draco, generateBoundingVolumes, geoidHeightModel, workerSource) {
76
+ async function convertB3dmToI3sGeometry(tileContent, addNodeToNodePage, propertyTable, featuresHashArray, attributeStorageInfo, draco, generateBoundingVolumes, shouldMergeMaterials, geoidHeightModel, workerSource) {
46
77
  const useCartesianPositions = generateBoundingVolumes;
47
- const materialAndTextureList = convertMaterials(tileContent.gltf?.materials);
78
+ const materialAndTextureList = await convertMaterials(tileContent.gltf?.materials, shouldMergeMaterials);
48
79
  const dataForAttributesConversion = (0, gltf_attributes_1.prepareDataForAttributesConversion)(tileContent);
49
- const convertedAttributesMap = await convertAttributes(dataForAttributesConversion, useCartesianPositions);
50
- // TODO uncomment it when worker will be published on CDN.
51
- /*
52
- const convertedAttributesMap: Map<string, ConvertedAttributes> =
53
- await transformI3SAttributesOnWorker(dataForAttributesConversion, {
54
- useCartesianPositions,
55
- source: workerSource.I3SAttributes
56
- });
57
- */
80
+ const convertedAttributesMap = await convertAttributes(dataForAttributesConversion, materialAndTextureList, useCartesianPositions);
81
+ /** Usage of worker here brings more overhead than advantage */
82
+ // const convertedAttributesMap: Map<string, ConvertedAttributes> =
83
+ // await transformI3SAttributesOnWorker(dataForAttributesConversion, {
84
+ // reuseWorkers: true,
85
+ // _nodeWorkers: true,
86
+ // useCartesianPositions,
87
+ // source: workerSource.I3SAttributes
88
+ // });
58
89
  if (generateBoundingVolumes) {
59
90
  _generateBoundingVolumesFromGeometry(convertedAttributesMap, geoidHeightModel);
60
91
  }
61
- if (convertedAttributesMap.has('default')) {
62
- materialAndTextureList.push({
63
- material: getDefaultMaterial()
64
- });
65
- }
66
92
  const result = [];
67
- let nodesCounter = nodeId;
68
- let { materials = [] } = tileContent.gltf || { materials: [] };
69
- if (!materials?.length) {
70
- materials.push({ id: 'default' });
71
- }
72
- for (let i = 0; i < materials.length; i++) {
73
- const sourceMaterial = materials[i];
74
- if (!convertedAttributesMap.has(sourceMaterial.id)) {
93
+ for (const materialAndTexture of materialAndTextureList) {
94
+ const originarMaterialId = materialAndTexture.mergedMaterials[0].originalMaterialId;
95
+ if (!convertedAttributesMap.has(originarMaterialId)) {
75
96
  continue; // eslint-disable-line no-continue
76
97
  }
77
- const convertedAttributes = convertedAttributesMap.get(sourceMaterial.id);
98
+ const convertedAttributes = convertedAttributesMap.get(originarMaterialId);
78
99
  if (!convertedAttributes) {
79
100
  continue;
80
101
  }
81
- const { material, texture } = materialAndTextureList[i];
102
+ const { material, texture } = materialAndTexture;
103
+ const nodeId = await addNodeToNodePage();
82
104
  result.push(await _makeNodeResources({
83
105
  convertedAttributes,
84
106
  material,
85
107
  texture,
86
108
  tileContent,
87
- nodeId: nodesCounter,
109
+ nodeId,
88
110
  featuresHashArray,
111
+ propertyTable,
89
112
  attributeStorageInfo,
90
113
  draco,
91
114
  workerSource
92
115
  }));
93
- nodesCounter++;
94
116
  }
95
117
  if (!result.length) {
96
118
  return null;
@@ -127,36 +149,44 @@ function _generateBoundingVolumesFromGeometry(convertedAttributesMap, geoidHeigh
127
149
  * @param params.tileContent - B3DM decoded content
128
150
  * @param params.nodeId - new node ID
129
151
  * @param params.featuresHashArray - hash array of features that is needed to not to mix up same features in parent and child nodes
130
- * @param params.attributesStorageInfo - attributes metadata from 3DSceneLayer json
152
+ * @param params.propertyTable - batch table (corresponding to feature attributes data)
153
+ * @param params.attributeStorageInfo - attributes metadata from 3DSceneLayer json
131
154
  * @param params.draco - is converter should create draco compressed geometry
155
+ * @param params.workerSource - source code of used workers
132
156
  * @returns Array of I3S node resources
133
157
  */
134
- async function _makeNodeResources({ convertedAttributes, material, texture, tileContent, nodeId, featuresHashArray, attributeStorageInfo, draco, workerSource }) {
158
+ async function _makeNodeResources({ convertedAttributes, material, texture, tileContent, nodeId, featuresHashArray, propertyTable, attributeStorageInfo, draco, workerSource }) {
135
159
  const boundingVolumes = convertedAttributes.boundingVolumes;
136
160
  const vertexCount = convertedAttributes.positions.length / VALUES_PER_VERTEX;
137
- const { faceRange, featureIds, positions, normals, colors, texCoords, featureCount } = (0, geometry_attributes_1.generateAttributes)(convertedAttributes);
161
+ const { faceRange, featureIds, positions, normals, colors, uvRegions, texCoords, featureCount } = (0, geometry_attributes_1.generateAttributes)(convertedAttributes);
138
162
  if (tileContent.batchTableJson) {
139
163
  makeFeatureIdsUnique(featureIds, convertedAttributes.featureIndices, featuresHashArray, tileContent.batchTableJson);
140
164
  }
141
165
  const header = new Uint32Array(2);
142
166
  const typedFeatureIds = generateBigUint64Array(featureIds);
143
167
  header.set([vertexCount, featureCount], 0);
144
- const fileBuffer = new Uint8Array((0, loader_utils_1.concatenateArrayBuffers)(header.buffer, positions.buffer, normals.buffer, texture ? texCoords.buffer : new ArrayBuffer(0), colors.buffer, typedFeatureIds.buffer, faceRange.buffer));
168
+ const fileBuffer = new Uint8Array((0, loader_utils_1.concatenateArrayBuffers)(header.buffer, positions.buffer, normals.buffer, texture ? texCoords.buffer : new ArrayBuffer(0), colors.buffer, uvRegions, typedFeatureIds.buffer, faceRange.buffer));
145
169
  const compressedGeometry = draco
146
170
  ? generateCompressedGeometry(vertexCount, convertedAttributes, {
147
171
  positions,
148
172
  normals,
149
173
  texCoords: texture ? texCoords : new Float32Array(0),
150
174
  colors,
175
+ uvRegions,
151
176
  featureIds,
152
177
  faceRange
153
178
  }, workerSource.draco)
154
179
  : null;
155
- const attributes = convertBatchTableToAttributeBuffers(tileContent.batchTableJson, featureIds, attributeStorageInfo);
180
+ let attributes = [];
181
+ if (attributeStorageInfo && propertyTable) {
182
+ attributes = convertPropertyTableToAttributeBuffers(featureIds, propertyTable, attributeStorageInfo);
183
+ }
156
184
  return {
185
+ nodeId,
157
186
  geometry: fileBuffer,
158
187
  compressedGeometry,
159
188
  texture,
189
+ hasUvRegions: Boolean(uvRegions.length),
160
190
  sharedResources: getSharedResources(tileContent.gltf?.materials || [], nodeId),
161
191
  meshMaterial: material,
162
192
  vertexCount,
@@ -167,26 +197,32 @@ async function _makeNodeResources({ convertedAttributes, material, texture, tile
167
197
  }
168
198
  /**
169
199
  * Convert attributes from the gltf nodes tree to i3s plain geometry
170
- * @param tileContent - 3d tile content
200
+ * @param attributesData - geometry attributes from gltf
201
+ * @param materialAndTextureList - array of data about materials and textures of the content
171
202
  * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
172
203
  * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
173
204
  * @returns map of converted geometry attributes
174
205
  */
175
- async function convertAttributes(attributesData, useCartesianPositions) {
176
- const { gltfMaterials, nodes, cartographicOrigin, cartesianModelMatrix } = attributesData;
206
+ async function convertAttributes(attributesData, materialAndTextureList, useCartesianPositions) {
207
+ const { nodes, images, cartographicOrigin, cartesianModelMatrix } = attributesData;
177
208
  const attributesMap = new Map();
178
- for (const material of gltfMaterials || [{ id: 'default' }]) {
179
- attributesMap.set(material.id, {
209
+ for (const materialAndTexture of materialAndTextureList) {
210
+ const attributes = {
180
211
  positions: new Float32Array(0),
181
212
  normals: new Float32Array(0),
182
213
  texCoords: new Float32Array(0),
183
214
  colors: new Uint8Array(0),
215
+ uvRegions: new Uint16Array(0),
184
216
  featureIndicesGroups: [],
185
217
  featureIndices: [],
186
- boundingVolumes: null
187
- });
218
+ boundingVolumes: null,
219
+ mergedMaterials: materialAndTexture.mergedMaterials
220
+ };
221
+ for (const mergedMaterial of materialAndTexture.mergedMaterials) {
222
+ attributesMap.set(mergedMaterial.originalMaterialId, attributes);
223
+ }
188
224
  }
189
- convertNodes(nodes, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions);
225
+ convertNodes(nodes, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions);
190
226
  for (const attrKey of attributesMap.keys()) {
191
227
  const attributes = attributesMap.get(attrKey);
192
228
  if (!attributes) {
@@ -208,17 +244,19 @@ exports.convertAttributes = convertAttributes;
208
244
  * Gltf has hierarchical structure of nodes. This function converts nodes starting from those which are in gltf scene object.
209
245
  * The goal is applying tranformation matrix for all children. Functions "convertNodes" and "convertNode" work together recursively.
210
246
  * @param nodes - gltf nodes array
211
- * @param tileContent - 3d tile content
247
+ * @param images - gltf images array
248
+ * @param cartographicOrigin - cartographic origin of bounding volume
249
+ * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic
212
250
  * @param attributesMap - for recursive concatenation of attributes
213
251
  * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
214
252
  * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
215
253
  * @param matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
216
254
  * @returns {void}
217
255
  */
218
- function convertNodes(nodes, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix = new core_1.Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
256
+ function convertNodes(nodes, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix = new core_1.Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
219
257
  if (nodes) {
220
258
  for (const node of nodes) {
221
- convertNode(node, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix);
259
+ convertNode(node, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix);
222
260
  }
223
261
  }
224
262
  }
@@ -248,25 +286,31 @@ function getCompositeTransformationMatrix(node, matrix) {
248
286
  /**
249
287
  * Convert all primitives of node and all children nodes
250
288
  * @param node - gltf node
251
- * @param {Object} tileContent - 3d tile content
289
+ * @param images - gltf images array
290
+ * @param cartographicOrigin - cartographic origin of bounding volume
291
+ * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic
252
292
  * @param {Map} attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
253
293
  * attributes
254
294
  * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
255
295
  * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
256
296
  * @param {Matrix4} matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
257
297
  */
258
- function convertNode(node, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix = new core_1.Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
298
+ function convertNode(node, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, matrix = new core_1.Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
259
299
  const transformationMatrix = getCompositeTransformationMatrix(node, matrix);
260
300
  const mesh = node.mesh;
261
301
  if (mesh) {
262
- convertMesh(mesh, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, transformationMatrix);
302
+ convertMesh(mesh, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, transformationMatrix);
263
303
  }
264
- convertNodes(node.children || [], cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, transformationMatrix);
304
+ convertNodes(node.children || [], images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions, transformationMatrix);
265
305
  }
266
306
  /**
267
- * Convert all primitives of node and all children nodes
268
- * @param mesh - gltf node
269
- * @param content - 3d tile content
307
+ * Convert all primitives of the mesh
308
+ * @param mesh - gltf mesh data
309
+ * @param images - gltf images array
310
+ * @param cartographicOrigin - cartographic origin of bounding volume
311
+ * @param cartesianModelMatrix - cartesian model matrix to convert coordinates to cartographic
312
+ * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
313
+ * attributes
270
314
  * @param useCartesianPositions - convert positions to absolute cartesian coordinates instead of cartographic offsets.
271
315
  * Cartesian coordinates will be required for creating bounding voulmest from geometry positions
272
316
  * @param attributesMap Map<{positions: Float32Array, normals: Float32Array, texCoords: Float32Array, colors: Uint8Array, featureIndices: Array}> - for recursive concatenation of
@@ -274,11 +318,13 @@ function convertNode(node, cartographicOrigin, cartesianModelMatrix, attributesM
274
318
 
275
319
  * @param {Matrix4} matrix - transformation matrix - cumulative transformation matrix formed from all parent node matrices
276
320
  */
277
- function convertMesh(mesh, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions = false, matrix = new core_1.Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
321
+ function convertMesh(mesh, images, cartographicOrigin, cartesianModelMatrix, attributesMap, useCartesianPositions = false, matrix = new core_1.Matrix4([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1])) {
278
322
  for (const primitive of mesh.primitives) {
279
323
  let outputAttributes = null;
324
+ let materialUvRegion;
280
325
  if (primitive.material) {
281
- outputAttributes = attributesMap.get(primitive.material.id);
326
+ outputAttributes = attributesMap.get(primitive.material.uniqueId);
327
+ materialUvRegion = outputAttributes?.mergedMaterials.find(({ originalMaterialId }) => originalMaterialId === primitive.material?.uniqueId)?.uvRegion;
282
328
  }
283
329
  else if (attributesMap.has('default')) {
284
330
  outputAttributes = attributesMap.get('default');
@@ -308,8 +354,11 @@ function convertMesh(mesh, cartographicOrigin, cartesianModelMatrix, attributesM
308
354
  }));
309
355
  outputAttributes.texCoords = (0, loader_utils_1.concatenateTypedArrays)(outputAttributes.texCoords, flattenTexCoords(attributes.TEXCOORD_0 && attributes.TEXCOORD_0.value, primitive.indices?.value));
310
356
  outputAttributes.colors = (0, loader_utils_1.concatenateTypedArrays)(outputAttributes.colors, flattenColors(attributes.COLOR_0, primitive.indices?.value));
357
+ if (materialUvRegion) {
358
+ outputAttributes.uvRegions = (0, loader_utils_1.concatenateTypedArrays)(outputAttributes.uvRegions, createUvRegion(materialUvRegion, primitive.indices?.value));
359
+ }
311
360
  outputAttributes.featureIndicesGroups = outputAttributes.featureIndicesGroups || [];
312
- outputAttributes.featureIndicesGroups.push(flattenBatchIds(getBatchIdsByAttributeName(attributes), primitive.indices?.value));
361
+ outputAttributes.featureIndicesGroups.push(flattenBatchIds(getBatchIds(attributes, primitive, images), primitive.indices?.value));
313
362
  }
314
363
  }
315
364
  /**
@@ -428,6 +477,19 @@ function flattenColors(colorsAttribute, indices) {
428
477
  }
429
478
  return newColors;
430
479
  }
480
+ /**
481
+ * Create per-vertex uv-region array
482
+ * @param materialUvRegion - uv-region fragment for a single vertex
483
+ * @param indices - geometry indices data
484
+ * @returns - uv-region array
485
+ */
486
+ function createUvRegion(materialUvRegion, indices) {
487
+ const result = new Uint16Array(indices.length * 4);
488
+ for (let i = 0; i < result.length; i += 4) {
489
+ result.set(materialUvRegion, i);
490
+ }
491
+ return result;
492
+ }
431
493
  /**
432
494
  * Flatten batchedIds list based on indices to right ordered array, compatible with i3s
433
495
  * @param batchedIds - gltf primitive
@@ -446,34 +508,123 @@ function flattenBatchIds(batchedIds, indices) {
446
508
  return newBatchIds;
447
509
  }
448
510
  /**
449
- * Return batchIds based on possible attribute names for different kind of maps.
450
- * @param attributes - the gltf primitive attributes
451
- * @returns batch ids attribute
511
+ * Get batchIds for featureIds creation
512
+ * @param attributes - gltf accessors
513
+ * @param primitive - gltf primitive data
514
+ * @param images - gltf texture images
452
515
  */
453
- function getBatchIdsByAttributeName(attributes) {
454
- let batchIds = [];
516
+ function getBatchIds(attributes, primitive, images) {
517
+ const batchIds = (0, batch_ids_extensions_1.handleBatchIdsExtensions)(attributes, primitive, images);
518
+ if (batchIds.length) {
519
+ return batchIds;
520
+ }
455
521
  for (let index = 0; index < BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES.length; index++) {
456
522
  const possibleBatchIdAttributeName = BATCHED_ID_POSSIBLE_ATTRIBUTE_NAMES[index];
457
523
  if (attributes[possibleBatchIdAttributeName] &&
458
524
  attributes[possibleBatchIdAttributeName].value) {
459
- batchIds = attributes[possibleBatchIdAttributeName].value;
460
- break;
525
+ return attributes[possibleBatchIdAttributeName].value;
461
526
  }
462
527
  }
463
- return batchIds;
528
+ return [];
464
529
  }
465
530
  /**
466
531
  * Convert GLTF material to I3S material definitions and textures
467
532
  * @param sourceMaterials Source GLTF materials
533
+ * @param shouldMergeMaterials - if true - the converter will try to merge similar materials
534
+ * to be able to merge primitives having those materials
468
535
  * @returns Array of Couples I3SMaterialDefinition + texture content
469
536
  */
470
- function convertMaterials(sourceMaterials = []) {
471
- const result = [];
537
+ async function convertMaterials(sourceMaterials = [], shouldMergeMaterials) {
538
+ let materials = [];
472
539
  for (const sourceMaterial of sourceMaterials) {
473
- result.push(convertMaterial(sourceMaterial));
540
+ materials.push(convertMaterial(sourceMaterial));
541
+ }
542
+ if (shouldMergeMaterials) {
543
+ materials = await mergeAllMaterials(materials);
544
+ }
545
+ return materials;
546
+ }
547
+ /**
548
+ * Merge materials when possible
549
+ * @param materials materials array
550
+ * @returns merged materials array
551
+ */
552
+ async function mergeAllMaterials(materials) {
553
+ const result = [];
554
+ while (materials.length > 0) {
555
+ let newMaterial = materials.splice(0, 1)[0];
556
+ const mergedIndices = [];
557
+ for (let i = 0; i < materials.length; i++) {
558
+ const material = materials[i];
559
+ if ((newMaterial.texture && material.texture) ||
560
+ (!newMaterial.texture && !material.texture)) {
561
+ newMaterial = await mergeMaterials(newMaterial, material);
562
+ mergedIndices.push(i);
563
+ }
564
+ }
565
+ if (newMaterial.texture && mergedIndices.length) {
566
+ const newWidth = newMaterial.mergedMaterials?.reduce((accum, { textureSize }) => accum + (textureSize?.width || 0), 0);
567
+ const newHeight = newMaterial.mergedMaterials?.reduce((accum, { textureSize }) => Math.max(accum, textureSize?.height || 0), 0);
568
+ let currentX = -1;
569
+ for (const aTextureMetadata of newMaterial.mergedMaterials) {
570
+ if (aTextureMetadata.textureSize) {
571
+ const newX = currentX +
572
+ 1 +
573
+ (aTextureMetadata.textureSize.width / newWidth) *
574
+ 2 ** (Uint16Array.BYTES_PER_ELEMENT * 8) -
575
+ 1;
576
+ aTextureMetadata.uvRegion = new Uint16Array([
577
+ currentX + 1,
578
+ 0,
579
+ newX,
580
+ (aTextureMetadata.textureSize.height / newHeight) *
581
+ 2 ** (Uint16Array.BYTES_PER_ELEMENT * 8) -
582
+ 1
583
+ ]);
584
+ currentX = newX;
585
+ }
586
+ }
587
+ newMaterial.texture.image.width = newWidth;
588
+ newMaterial.texture.image.height = newHeight;
589
+ }
590
+ for (const index of mergedIndices.reverse()) {
591
+ materials.splice(index, 1);
592
+ }
593
+ result.push(newMaterial);
594
+ }
595
+ if (!result.length) {
596
+ result.push({
597
+ material: getDefaultMaterial(),
598
+ mergedMaterials: [{ originalMaterialId: 'default' }]
599
+ });
474
600
  }
475
601
  return result;
476
602
  }
603
+ /**
604
+ * Merge 2 materials including texture
605
+ * @param material1
606
+ * @param material2
607
+ * @returns
608
+ */
609
+ async function mergeMaterials(material1, material2) {
610
+ if (material1.texture?.bufferView &&
611
+ material2.texture?.bufferView &&
612
+ material1.mergedMaterials &&
613
+ material2.mergedMaterials) {
614
+ const buffer1 = Buffer.from(material1.texture.bufferView.data);
615
+ const buffer2 = Buffer.from(material2.texture.bufferView.data);
616
+ // @ts-ignore
617
+ const { joinImages } = await Promise.resolve().then(() => __importStar(require('join-images')));
618
+ const sharpData = await joinImages([buffer1, buffer2], { direction: 'horizontal' });
619
+ material1.texture.bufferView.data = await sharpData
620
+ .toFormat(material1.texture.mimeType === 'image/png' ? 'png' : 'jpeg')
621
+ .toBuffer();
622
+ // @ts-ignore
623
+ material1.material.pbrMetallicRoughness.baseColorTexture.textureSetDefinitionId = 1;
624
+ }
625
+ material1.mergedMaterials = material1.mergedMaterials.concat(material2.mergedMaterials);
626
+ return material1;
627
+ }
477
628
  /**
478
629
  * Convert texture and material from gltf 2.0 material object
479
630
  * @param sourceMaterial - material object
@@ -505,6 +656,9 @@ function convertMaterial(sourceMaterial) {
505
656
  textureSetDefinitionId: 0
506
657
  };
507
658
  }
659
+ const uniqueId = (0, uuid_1.v4)();
660
+ sourceMaterial.uniqueId = uniqueId;
661
+ let mergedMaterials = [{ originalMaterialId: uniqueId }];
508
662
  if (!texture) {
509
663
  // Should use default baseColorFactor if it is not present in source material
510
664
  // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-pbrmetallicroughness
@@ -512,7 +666,10 @@ function convertMaterial(sourceMaterial) {
512
666
  material.pbrMetallicRoughness.baseColorFactor =
513
667
  (baseColorFactor && baseColorFactor.map((c) => Math.round(c * 255))) || undefined;
514
668
  }
515
- return { material, texture };
669
+ else {
670
+ mergedMaterials[0].textureSize = { width: texture.image.width, height: texture.image.height };
671
+ }
672
+ return { material, texture, mergedMaterials };
516
673
  }
517
674
  /**
518
675
  * Converts from `alphaMode` material property from GLTF to I3S format
@@ -621,7 +778,9 @@ function extractSharedResourcesMaterialInfo(baseColorFactor, metallicFactor = 1)
621
778
  const specular = dielectricSpecular.lerp(dielectricSpecular, baseColorVector, metallicFactor);
622
779
  return {
623
780
  params: {
781
+ // @ts-expect-error NumericArray
624
782
  diffuse: diffuse.toArray(),
783
+ // @ts-expect-error NumericArray
625
784
  specular: specular.toArray(),
626
785
  renderMode: 'solid'
627
786
  }
@@ -648,7 +807,7 @@ function extractSharedResourcesTextureInfo(texture, nodeId) {
648
807
  };
649
808
  }
650
809
  /**
651
- * Formula for counting imageId:
810
+ * Formula for calculating imageId:
652
811
  * https://github.com/Esri/i3s-spec/blob/0a6366a9249b831db8436c322f8d27521e86cf07/format/Indexed%203d%20Scene%20Layer%20Format%20Specification.md#generating-image-ids
653
812
  * @param texture - texture image info
654
813
  * @param nodeId - I3S node ID
@@ -738,43 +897,53 @@ function replaceIndicesByUnique(indicesArray, featureMap) {
738
897
  }
739
898
  }
740
899
  /**
741
- * Convert batch table data to attribute buffers.
742
- * @param {Object} batchTable - table with metadata for particular feature.
900
+ * Convert property table data to attribute buffers.
743
901
  * @param {Array} featureIds
902
+ * @param {Object} propertyTable - table with metadata for particular feature.
744
903
  * @param {Array} attributeStorageInfo
745
904
  * @returns {Array} - Array of file buffers.
746
905
  */
747
- function convertBatchTableToAttributeBuffers(batchTable, featureIds, attributeStorageInfo) {
906
+ function convertPropertyTableToAttributeBuffers(featureIds, propertyTable, attributeStorageInfo) {
748
907
  const attributeBuffers = [];
749
- if (batchTable) {
750
- const batchTableWithFeatureIds = {
751
- OBJECTID: featureIds,
752
- ...batchTable
753
- };
754
- for (const key in batchTableWithFeatureIds) {
755
- const type = getAttributeType(key, attributeStorageInfo);
756
- let attributeBuffer = null;
757
- switch (type) {
758
- case OBJECT_ID_TYPE:
759
- case SHORT_INT_TYPE:
760
- attributeBuffer = generateShortIntegerAttributeBuffer(batchTableWithFeatureIds[key]);
761
- break;
762
- case DOUBLE_TYPE:
763
- attributeBuffer = generateDoubleAttributeBuffer(batchTableWithFeatureIds[key]);
764
- break;
765
- case STRING_TYPE:
766
- attributeBuffer = generateStringAttributeBuffer(batchTableWithFeatureIds[key]);
767
- break;
768
- default:
769
- attributeBuffer = generateStringAttributeBuffer(batchTableWithFeatureIds[key]);
770
- }
771
- if (attributeBuffer) {
772
- attributeBuffers.push(attributeBuffer);
773
- }
774
- }
908
+ const needFlattenPropertyTable = (0, feature_attributes_1.checkPropertiesLength)(featureIds, propertyTable);
909
+ const properties = needFlattenPropertyTable
910
+ ? (0, feature_attributes_1.flattenPropertyTableByFeatureIds)(featureIds, propertyTable)
911
+ : propertyTable;
912
+ const propertyTableWithObjectIds = {
913
+ OBJECTID: featureIds,
914
+ ...properties
915
+ };
916
+ for (const propertyName in propertyTableWithObjectIds) {
917
+ const type = getAttributeType(propertyName, attributeStorageInfo);
918
+ const value = propertyTableWithObjectIds[propertyName];
919
+ const attributeBuffer = generateAttributeBuffer(type, value);
920
+ attributeBuffers.push(attributeBuffer);
775
921
  }
776
922
  return attributeBuffers;
777
923
  }
924
+ /**
925
+ * Generates attribute buffer based on attribute type
926
+ * @param type
927
+ * @param value
928
+ */
929
+ function generateAttributeBuffer(type, value) {
930
+ let attributeBuffer;
931
+ switch (type) {
932
+ case OBJECT_ID_TYPE:
933
+ case SHORT_INT_TYPE:
934
+ attributeBuffer = generateShortIntegerAttributeBuffer(value);
935
+ break;
936
+ case DOUBLE_TYPE:
937
+ attributeBuffer = generateDoubleAttributeBuffer(value);
938
+ break;
939
+ case STRING_TYPE:
940
+ attributeBuffer = generateStringAttributeBuffer(value);
941
+ break;
942
+ default:
943
+ attributeBuffer = generateStringAttributeBuffer(value);
944
+ }
945
+ return attributeBuffer;
946
+ }
778
947
  /**
779
948
  * Return attribute type.
780
949
  * @param {String} key
@@ -848,7 +1017,7 @@ function generateBigUint64Array(featureIds) {
848
1017
  * @returns {Promise<object>} - COmpressed geometry.
849
1018
  */
850
1019
  async function generateCompressedGeometry(vertexCount, convertedAttributes, attributes, dracoWorkerSoure) {
851
- const { positions, normals, texCoords, colors, featureIds, faceRange } = attributes;
1020
+ const { positions, normals, texCoords, colors, uvRegions, featureIds, faceRange } = attributes;
852
1021
  const indices = new Uint32Array(vertexCount);
853
1022
  for (let index = 0; index < indices.length; index++) {
854
1023
  indices.set([index], index);
@@ -870,6 +1039,12 @@ async function generateCompressedGeometry(vertexCount, convertedAttributes, attr
870
1039
  'i3s-feature-ids': new Int32Array(featureIds)
871
1040
  }
872
1041
  };
1042
+ if (uvRegions.length) {
1043
+ compressedAttributes['uv-region'] = uvRegions;
1044
+ attributesMetadata['uv-region'] = {
1045
+ 'i3s-attribute-type': 'uv-region'
1046
+ };
1047
+ }
873
1048
  return (0, core_2.encode)({ attributes: compressedAttributes, indices }, draco_1.DracoWriterWorker, {
874
1049
  ...draco_1.DracoWriterWorker.options,
875
1050
  source: dracoWorkerSoure,
@@ -899,3 +1074,78 @@ function generateFeatureIndexAttribute(featureIndex, faceRange) {
899
1074
  }
900
1075
  return orderedFeatureIndices;
901
1076
  }
1077
+ /**
1078
+ * Find property table in tile
1079
+ * For example it can be batchTable for b3dm files or property table in gLTF extension.
1080
+ * @param sourceTile
1081
+ * @return batch table from b3dm / feature properties from EXT_FEATURE_METADATA
1082
+ */
1083
+ function getPropertyTable(tileContent) {
1084
+ const batchTableJson = tileContent?.batchTableJson;
1085
+ if (batchTableJson) {
1086
+ return batchTableJson;
1087
+ }
1088
+ const { extensionName, extension } = getPropertyTableExtension(tileContent);
1089
+ switch (extensionName) {
1090
+ case EXT_MESH_FEATURES: {
1091
+ console.warn('The I3S converter does not yet support the EXT_mesh_features extension');
1092
+ return null;
1093
+ }
1094
+ case EXT_FEATURE_METADATA: {
1095
+ return getPropertyTableFromExtFeatureMetadata(extension);
1096
+ }
1097
+ default:
1098
+ return null;
1099
+ }
1100
+ }
1101
+ exports.getPropertyTable = getPropertyTable;
1102
+ /**
1103
+ * Check extensions which can be with property table inside.
1104
+ * @param sourceTile
1105
+ */
1106
+ function getPropertyTableExtension(tileContent) {
1107
+ const extensionsWithPropertyTables = [EXT_FEATURE_METADATA, EXT_MESH_FEATURES];
1108
+ const extensionsUsed = tileContent?.gltf?.extensionsUsed;
1109
+ if (!extensionsUsed) {
1110
+ return { extensionName: null, extension: null };
1111
+ }
1112
+ let extensionName = '';
1113
+ for (const extensionItem of tileContent?.gltf?.extensionsUsed || []) {
1114
+ if (extensionsWithPropertyTables.includes(extensionItem)) {
1115
+ extensionName = extensionItem;
1116
+ break;
1117
+ }
1118
+ }
1119
+ const extension = tileContent?.gltf?.extensions?.[extensionName];
1120
+ return { extensionName, extension };
1121
+ }
1122
+ /**
1123
+ * Handle EXT_feature_metadata to get property table
1124
+ * @param extension
1125
+ * TODO add EXT_feature_metadata feature textures support.
1126
+ */
1127
+ function getPropertyTableFromExtFeatureMetadata(extension) {
1128
+ if (extension?.featureTextures) {
1129
+ console.warn('The I3S converter does not yet support the EXT_feature_metadata feature textures');
1130
+ return null;
1131
+ }
1132
+ if (extension?.featureTables) {
1133
+ /**
1134
+ * Take only first feature table to generate attributes storage info object.
1135
+ * TODO: Think about getting data from all feature tables?
1136
+ * It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables.
1137
+ * In I3S we should decide which featureIds attribute will be passed to geometry data.
1138
+ */
1139
+ const firstFeatureTableName = Object.keys(extension.featureTables)?.[0];
1140
+ if (firstFeatureTableName) {
1141
+ const featureTable = extension?.featureTables[firstFeatureTableName];
1142
+ const propertyTable = {};
1143
+ for (const propertyName in featureTable.properties) {
1144
+ propertyTable[propertyName] = featureTable.properties[propertyName].data;
1145
+ }
1146
+ return propertyTable;
1147
+ }
1148
+ }
1149
+ console.warn("The I3S converter couldn't handle EXT_feature_metadata extension");
1150
+ return null;
1151
+ }