@xeokit/xeokit-sdk 2.5.2-beta-4 → 2.5.2-beta-7

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.
@@ -1,4 +1,5 @@
1
1
  import {Plugin} from "../../viewer/Plugin.js";
2
+ import {RenderService} from "./RenderService.js";
2
3
 
3
4
  const treeViews = [];
4
5
 
@@ -359,6 +360,7 @@ export class TreeViewPlugin extends Plugin {
359
360
  * ````IfcBuildingStorey```` nodes will be ordered spatially, from the highest storey down to the lowest, on the
360
361
  * vertical World axis. For all hierarchy types, other node types will be ordered in the ascending alphanumeric order of their titles.
361
362
  * @param {Boolean} [cfg.pruneEmptyNodes=true] When true, will not contain nodes that don't have content in the {@link Scene}. These are nodes whose {@link MetaObject}s don't have {@link Entity}s.
363
+ * @param {RenderService} [cfg.renderService] Optional {@link RenderService} to use. Defaults to the {@link TreeViewPlugin}'s default {@link RenderService}.
362
364
  */
363
365
  constructor(viewer, cfg = {}) {
364
366
 
@@ -398,7 +400,6 @@ export class TreeViewPlugin extends Plugin {
398
400
  this._autoAddModels = (cfg.autoAddModels !== false);
399
401
  this._autoExpandDepth = (cfg.autoExpandDepth || 0);
400
402
  this._sortNodes = (cfg.sortNodes !== false);
401
- this._pruneEmptyNodes = (cfg.pruneEmptyNodes !== false);
402
403
  this._viewer = viewer;
403
404
  this._rootElement = null;
404
405
  this._muteSceneEvents = false;
@@ -406,10 +407,15 @@ export class TreeViewPlugin extends Plugin {
406
407
  this._rootNodes = [];
407
408
  this._objectNodes = {}; // Object ID -> Node
408
409
  this._nodeNodes = {}; // Node ID -> Node
409
- this._rootName = cfg.rootName;
410
+ this._rootNames = {}; // Node ID -> Root name
410
411
  this._sortNodes = cfg.sortNodes;
411
412
  this._pruneEmptyNodes = cfg.pruneEmptyNodes;
412
413
  this._showListItemElementId = null;
414
+ this._renderService = cfg.renderService || new RenderService();
415
+
416
+ if (!this._renderService) {
417
+ throw new Error('TreeViewPlugin: no render service set');
418
+ }
413
419
 
414
420
  this._containerElement.oncontextmenu = (e) => {
415
421
  e.preventDefault();
@@ -436,10 +442,9 @@ export class TreeViewPlugin extends Plugin {
436
442
  } else {
437
443
  node.numVisibleEntities--;
438
444
  }
439
- const checkbox = document.getElementById(`checkbox-${node.nodeId}`);
440
- if (checkbox) {
441
- checkbox.checked = visible;
442
- }
445
+
446
+ this._renderService.setCheckbox(node.nodeId, visible);
447
+
443
448
  let parent = node.parent;
444
449
  while (parent) {
445
450
  parent.checked = visible;
@@ -448,15 +453,12 @@ export class TreeViewPlugin extends Plugin {
448
453
  } else {
449
454
  parent.numVisibleEntities--;
450
455
  }
451
- const parentCheckbox = document.getElementById(`checkbox-${parent.nodeId}`);
452
- if (parentCheckbox) {
453
- const newChecked = (parent.numVisibleEntities > 0);
454
- if (newChecked !== parentCheckbox.checked) {
455
- parentCheckbox.checked = newChecked;
456
- }
457
- }
456
+
457
+ this._renderService.setCheckbox(parent.nodeId, (parent.numVisibleEntities > 0));
458
+
458
459
  parent = parent.parent;
459
460
  }
461
+
460
462
  this._muteTreeEvents = false;
461
463
  });
462
464
 
@@ -476,15 +478,8 @@ export class TreeViewPlugin extends Plugin {
476
478
  return;
477
479
  }
478
480
  node.xrayed = xrayed;
479
- const listItemElementId = node.nodeId;
480
- const listItemElement = document.getElementById(listItemElementId);
481
- if (listItemElement !== null) {
482
- if (xrayed) {
483
- listItemElement.classList.add('xrayed-node');
484
- } else {
485
- listItemElement.classList.remove('xrayed-node');
486
- }
487
- }
481
+
482
+ this._renderService.setXRayed(node.nodeId, xrayed);
488
483
  this._muteTreeEvents = false;
489
484
  });
490
485
 
@@ -508,14 +503,15 @@ export class TreeViewPlugin extends Plugin {
508
503
  }
509
504
  this._muteSceneEvents = true;
510
505
  const checkbox = event.target;
511
- const visible = checkbox.checked;
512
- const nodeId = checkbox.id.replace('checkbox-', '');
506
+ const visible = this._renderService.isChecked(checkbox);
507
+ const nodeId = this._renderService.getIdFromCheckbox(checkbox);
508
+
513
509
  const checkedNode = this._nodeNodes[nodeId];
514
510
  const objects = this._viewer.scene.objects;
515
511
  let numUpdated = 0;
512
+
516
513
  this._withNodeTree(checkedNode, (node) => {
517
514
  const objectId = node.objectId;
518
- const checkBoxId = `checkbox-${node.nodeId}`;
519
515
  const entity = objects[objectId];
520
516
  const isLeaf = (node.children.length === 0);
521
517
  node.numVisibleEntities = visible ? node.numEntities : 0;
@@ -523,27 +519,26 @@ export class TreeViewPlugin extends Plugin {
523
519
  numUpdated++;
524
520
  }
525
521
  node.checked = visible;
526
- const checkbox2 = document.getElementById(checkBoxId);
527
- if (checkbox2) {
528
- checkbox2.checked = visible;
529
- }
522
+
523
+ this._renderService.setCheckbox(node.nodeId, visible);
524
+
530
525
  if (entity) {
531
526
  entity.visible = visible;
532
527
  }
533
528
  });
529
+
534
530
  let parent = checkedNode.parent;
535
531
  while (parent) {
536
532
  parent.checked = visible;
537
- const checkbox2 = document.getElementById(`checkbox-${parent.nodeId}`); // Parent checkboxes are always in DOM
533
+
538
534
  if (visible) {
539
535
  parent.numVisibleEntities += numUpdated;
540
536
  } else {
541
537
  parent.numVisibleEntities -= numUpdated;
542
538
  }
543
- const newChecked = (parent.numVisibleEntities > 0);
544
- if (newChecked !== checkbox2.checked) {
545
- checkbox2.checked = newChecked;
546
- }
539
+
540
+ this._renderService.setCheckbox(parent.nodeId, (parent.numVisibleEntities > 0));
541
+
547
542
  parent = parent.parent;
548
543
  }
549
544
  this._muteSceneEvents = false;
@@ -641,6 +636,11 @@ export class TreeViewPlugin extends Plugin {
641
636
  return;
642
637
  }
643
638
  this._metaModels[modelId] = metaModel;
639
+
640
+ if (options && options.rootName) {
641
+ this._rootNames[modelId] = options.rootName;
642
+ }
643
+
644
644
  model.on("destroyed", () => {
645
645
  this.removeModel(model.id);
646
646
  });
@@ -662,6 +662,11 @@ export class TreeViewPlugin extends Plugin {
662
662
  if (!metaModel) {
663
663
  return;
664
664
  }
665
+
666
+ if (this._rootNames[modelId]) {
667
+ delete this._rootNames[modelId];
668
+ }
669
+
665
670
  delete this._metaModels[modelId];
666
671
  this._createNodes();
667
672
  }
@@ -683,21 +688,22 @@ export class TreeViewPlugin extends Plugin {
683
688
  * @param {String} objectId ID of the {@link Entity}.
684
689
  */
685
690
  showNode(objectId) {
686
- if (this._showListItemElementId) {
687
- this.unShowNode();
688
- }
691
+ this.unShowNode();
692
+
689
693
  const node = this._objectNodes[objectId];
690
694
  if (!node) {
691
695
  return; // Node may not exist for the given object if (this._pruneEmptyNodes == true)
692
696
  }
697
+
693
698
  const nodeId = node.nodeId;
694
- const switchElementId = "switch-" + nodeId;
695
- const switchElement = document.getElementById(switchElementId);
699
+
700
+ const switchElement = this._renderService.getSwitchElement(nodeId);
696
701
  if (switchElement) {
697
702
  this._expandSwitchElement(switchElement);
698
703
  switchElement.scrollIntoView();
699
- return;
704
+ return true;
700
705
  }
706
+
701
707
  const path = [];
702
708
  path.unshift(node);
703
709
  let parent = node.parent;
@@ -705,20 +711,17 @@ export class TreeViewPlugin extends Plugin {
705
711
  path.unshift(parent);
706
712
  parent = parent.parent;
707
713
  }
714
+
708
715
  for (let i = 0, len = path.length; i < len; i++) {
709
- const node = path[i];
710
- const nodeId = node.nodeId;
711
- const switchElementId = "switch-" + nodeId;
712
- const switchElement = document.getElementById(switchElementId);
716
+ const switchElement = this._renderService.getSwitchElement(path[i].nodeId);
713
717
  if (switchElement) {
714
718
  this._expandSwitchElement(switchElement);
715
719
  }
716
720
  }
717
- const listItemElementId = nodeId;
718
- const listItemElement = document.getElementById(listItemElementId);
719
- listItemElement.scrollIntoView({block: "center"});
720
- listItemElement.classList.add("highlighted-node");
721
- this._showListItemElementId = listItemElementId;
721
+
722
+ this._renderService.setHighlighted(nodeId, true);
723
+
724
+ this._showListItemElementId = nodeId;
722
725
  }
723
726
 
724
727
  /**
@@ -732,12 +735,9 @@ export class TreeViewPlugin extends Plugin {
732
735
  if (!this._showListItemElementId) {
733
736
  return;
734
737
  }
735
- const listItemElement = document.getElementById(this._showListItemElementId);
736
- if (!listItemElement) {
737
- this._showListItemElementId = null;
738
- return;
739
- }
740
- listItemElement.classList.remove("highlighted-node");
738
+
739
+ this._renderService.setHighlighted(this._showListItemElementId, false)
740
+
741
741
  this._showListItemElementId = null;
742
742
  }
743
743
 
@@ -754,9 +754,8 @@ export class TreeViewPlugin extends Plugin {
754
754
  if (countDepth === depth) {
755
755
  return;
756
756
  }
757
- const nodeId = node.nodeId;
758
- const switchElementId = "switch-" + nodeId;
759
- const switchElement = document.getElementById(switchElementId);
757
+
758
+ const switchElement = this._renderService.getSwitchElement(node.nodeId);
760
759
  if (switchElement) {
761
760
  this._expandSwitchElement(switchElement);
762
761
  const childNodes = node.children;
@@ -911,11 +910,12 @@ export class TreeViewPlugin extends Plugin {
911
910
 
912
911
  _createDisabledNodes() {
913
912
 
914
- const ul = document.createElement('ul');
915
- this._rootElement = ul;
916
- this._containerElement.appendChild(ul);
913
+ const rootNode = this._renderService.createRootNode();
914
+ this._rootElement = rootNode;
915
+ this._containerElement.appendChild(rootNode);
917
916
 
918
917
  const rootMetaObjects = this._viewer.metaScene.rootMetaObjects;
918
+
919
919
  for (let objectId in rootMetaObjects) {
920
920
  const rootMetaObject = rootMetaObjects[objectId];
921
921
  const metaObjectType = rootMetaObject.type;
@@ -923,17 +923,9 @@ export class TreeViewPlugin extends Plugin {
923
923
  const rootName = ((metaObjectName && metaObjectName !== ""
924
924
  && metaObjectName !== "Undefined"
925
925
  && metaObjectName !== "Default") ? metaObjectName : metaObjectType);
926
- const li = document.createElement('li');
927
- ul.appendChild(li);
928
- const switchElement = document.createElement('a');
929
- switchElement.href = '#';
930
- switchElement.textContent = '!';
931
- switchElement.classList.add('warn');
932
- switchElement.classList.add('warning');
933
- li.appendChild(switchElement);
934
- const span = document.createElement('span');
935
- span.textContent = rootName;
936
- li.appendChild(span);
926
+
927
+ const childNode = this._renderService.createDisabledNodeElement(rootName);
928
+ rootNode.appendChild(childNode);
937
929
  }
938
930
  }
939
931
 
@@ -984,7 +976,7 @@ export class TreeViewPlugin extends Plugin {
984
976
  buildingNode = {
985
977
  nodeId: `${this._id}-${objectId}`,
986
978
  objectId: objectId,
987
- title: this._rootName || ((metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType),
979
+ title: this._rootNames[metaObject.metaModels[0].id] || ((metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType),
988
980
  type: metaObjectType,
989
981
  parent: null,
990
982
  numEntities: 0,
@@ -1087,7 +1079,7 @@ export class TreeViewPlugin extends Plugin {
1087
1079
  rootNode = {
1088
1080
  nodeId: `${this._id}-${objectId}`,
1089
1081
  objectId: objectId,
1090
- title: this._rootName || ((metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType),
1082
+ title: this._rootNames[metaObject.metaModels[0].id] || ((metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType),
1091
1083
  type: metaObjectType,
1092
1084
  parent: null,
1093
1085
  numEntities: 0,
@@ -1168,7 +1160,7 @@ export class TreeViewPlugin extends Plugin {
1168
1160
  const node = {
1169
1161
  nodeId: `${this._id}-${objectId}`,
1170
1162
  objectId: objectId,
1171
- title: (!parent) ? (this._rootName || metaObjectName) : (metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType,
1163
+ title: (!parent) ? (this._rootNames[metaObject.metaModels[0].id] || metaObjectName) : (metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType,
1172
1164
  type: metaObjectType,
1173
1165
  parent: parent,
1174
1166
  numEntities: 0,
@@ -1316,112 +1308,63 @@ export class TreeViewPlugin extends Plugin {
1316
1308
  const rootNodeElements = this._rootNodes.map((rootNode) => {
1317
1309
  return this._createNodeElement(rootNode);
1318
1310
  });
1319
- const ul = document.createElement('ul');
1311
+
1312
+ const rootNode = this._renderService.createRootNode();
1320
1313
  rootNodeElements.forEach((nodeElement) => {
1321
- ul.appendChild(nodeElement);
1314
+ rootNode.appendChild(nodeElement);
1322
1315
  });
1323
- this._containerElement.appendChild(ul);
1324
- this._rootElement = ul;
1316
+
1317
+ this._containerElement.appendChild(rootNode);
1318
+ this._rootElement = rootNode;
1325
1319
  }
1326
1320
 
1327
1321
  _createNodeElement(node) {
1328
- const nodeElement = document.createElement('li');
1329
- //const nodeId = this._objectToNodeID(node.objectId);
1330
- const nodeId = node.nodeId;
1331
- if (node.xrayed) {
1332
- nodeElement.classList.add('xrayed-node');
1333
- }
1334
- nodeElement.id = nodeId;
1335
- if (node.children.length > 0) {
1336
- const switchElementId = "switch-" + nodeId;
1337
- const switchElement = document.createElement('a');
1338
- switchElement.href = '#';
1339
- switchElement.id = switchElementId;
1340
- switchElement.textContent = '+';
1341
- switchElement.classList.add('plus');
1342
- switchElement.addEventListener('click', this._switchExpandHandler);
1343
- nodeElement.appendChild(switchElement);
1344
- }
1345
- const checkbox = document.createElement('input');
1346
- checkbox.id = `checkbox-${nodeId}`;
1347
- checkbox.type = "checkbox";
1348
- checkbox.checked = node.checked;
1349
- checkbox.style["pointer-events"] = "all";
1350
- checkbox.addEventListener("change", this._checkboxChangeHandler);
1351
- nodeElement.appendChild(checkbox);
1352
- const span = document.createElement('span');
1353
- span.textContent = node.title;
1354
- nodeElement.appendChild(span);
1355
- span.oncontextmenu = (e) => {
1356
- this.fire("contextmenu", {
1357
- event: e,
1322
+ const contextmenuHandler = (event) =>{
1323
+ this.fire("contextmenu", {
1324
+ event: event,
1358
1325
  viewer: this._viewer,
1359
1326
  treeViewPlugin: this,
1360
1327
  treeViewNode: node
1361
1328
  });
1362
- e.preventDefault();
1329
+ event.preventDefault();
1363
1330
  };
1364
- span.onclick = (e) => {
1331
+ const onclickHandler = (event) => {
1365
1332
  this.fire("nodeTitleClicked", {
1366
- event: e,
1333
+ event: event,
1367
1334
  viewer: this._viewer,
1368
1335
  treeViewPlugin: this,
1369
1336
  treeViewNode: node
1370
1337
  });
1371
- e.preventDefault();
1338
+ event.preventDefault();
1372
1339
  };
1373
- return nodeElement;
1340
+
1341
+ return this._renderService.createNodeElement(node, this._switchExpandHandler, this._checkboxChangeHandler, contextmenuHandler, onclickHandler);
1374
1342
  }
1375
1343
 
1376
1344
  _expandSwitchElement(switchElement) {
1377
- const parentElement = switchElement.parentElement;
1378
- const expanded = parentElement.getElementsByTagName('li')[0];
1345
+ const expanded = this._renderService.isExpanded(switchElement);
1379
1346
  if (expanded) {
1380
1347
  return;
1381
1348
  }
1382
- const nodeId = parentElement.id;
1383
- const switchNode = this._nodeNodes[nodeId];
1384
- const childNodes = switchNode.children;
1385
- const nodeElements = childNodes.map((node) => {
1349
+
1350
+ const nodeId = this._renderService.getId(switchElement);
1351
+
1352
+ const nodeElements = this._nodeNodes[nodeId].children.map((node) => {
1386
1353
  return this._createNodeElement(node);
1387
1354
  });
1388
- const ul = document.createElement('ul');
1389
- nodeElements.forEach((nodeElement) => {
1390
- ul.appendChild(nodeElement);
1391
- });
1392
- parentElement.appendChild(ul);
1393
- switchElement.classList.remove('plus');
1394
- switchElement.classList.add('minus');
1395
- switchElement.textContent = '-';
1396
- switchElement.removeEventListener('click', this._switchExpandHandler);
1397
- switchElement.addEventListener('click', this._switchCollapseHandler);
1355
+
1356
+ this._renderService.addChildren(switchElement, nodeElements)
1357
+
1358
+ this._renderService.expand(switchElement, this._switchExpandHandler, this._switchCollapseHandler);
1398
1359
  }
1399
1360
 
1400
- _collapseNode(objectId) {
1401
- const nodeId = objectId;
1402
- const switchElementId = "switch-" + nodeId;
1403
- const switchElement = document.getElementById(switchElementId);
1361
+ _collapseNode(nodeId) {
1362
+ const switchElement = this._renderService.getSwitchElement(nodeId);
1404
1363
  this._collapseSwitchElement(switchElement);
1405
1364
  }
1406
1365
 
1407
1366
  _collapseSwitchElement(switchElement) {
1408
- if (!switchElement) {
1409
- return;
1410
- }
1411
- const parent = switchElement.parentElement;
1412
- if (!parent) {
1413
- return;
1414
- }
1415
- const ul = parent.querySelector('ul');
1416
- if (!ul) {
1417
- return;
1418
- }
1419
- parent.removeChild(ul);
1420
- switchElement.classList.remove('minus');
1421
- switchElement.classList.add('plus');
1422
- switchElement.textContent = '+';
1423
- switchElement.removeEventListener('click', this._switchCollapseHandler);
1424
- switchElement.addEventListener('click', this._switchExpandHandler);
1367
+ this._renderService.collapse(switchElement, this._switchExpandHandler, this._switchCollapseHandler);
1425
1368
  }
1426
1369
  }
1427
1370
 
@@ -355,9 +355,9 @@ parsers[ParserV10.version] = ParserV10;
355
355
  * }
356
356
  *
357
357
  * // Gets the contents of the given .XKT file in an arraybuffer
358
- * getXKT(src, ok, error) {
358
+ * getXKT(xKTSrc, ok, error) {
359
359
  * console.log("MyDataSource#getXKT(" + xKTSrc + ", ... )");
360
- * utils.loadArraybuffer(src,
360
+ * utils.loadArraybuffer(xKTSrc,
361
361
  * (arraybuffer) => {
362
362
  * ok(arraybuffer);
363
363
  * },
@@ -1146,8 +1146,6 @@ export class SceneModel extends Component {
1146
1146
  this._vboBatchingLayers = {};
1147
1147
  this._dtxLayers = {};
1148
1148
 
1149
- this._meshList = [];
1150
-
1151
1149
  this.layerList = []; // For GL state efficiency when drawing, InstancingLayers are in first part, BatchingLayers are in second
1152
1150
  this._entityList = [];
1153
1151
 
@@ -1159,7 +1157,8 @@ export class SceneModel extends Component {
1159
1157
  this._meshes = {};
1160
1158
  this._entities = {};
1161
1159
 
1162
- this._scheduledMeshes = {}
1160
+ this._scheduledMeshes = {};
1161
+ this._meshesCfgsBeforeMeshCreation = {};
1163
1162
 
1164
1163
  /** @private **/
1165
1164
  this.renderFlags = new RenderFlags();
@@ -2690,7 +2689,7 @@ export class SceneModel extends Component {
2690
2689
  /**
2691
2690
  * Creates a new {@link SceneModelMesh} within this SceneModel.
2692
2691
  *
2693
- * * Stores the new SceneModelMesh in {@link SceneModel#meshes}.
2692
+ * * It prepares and saves data for a SceneModelMesh {@link SceneModel#meshes} creation. SceneModelMesh will be created only once the SceneModelEntity (which references this particular SceneModelMesh) will be created.
2694
2693
  * * The SceneModelMesh can either define its own geometry or share it with other SceneModelMeshes. To define own geometry, provide the
2695
2694
  * various geometry arrays to this method. To share a geometry, provide the ID of a geometry created earlier
2696
2695
  * with {@link SceneModel#createGeometry}.
@@ -2725,18 +2724,18 @@ export class SceneModel extends Component {
2725
2724
  * @param {Number} [cfg.opacity=1] Opacity in range ````[0..1]````. Overridden by texture set ````colorTexture````.
2726
2725
  * @param {Number} [cfg.metallic=0] Metallic factor in range ````[0..1]````. Overridden by texture set ````metallicRoughnessTexture````.
2727
2726
  * @param {Number} [cfg.roughness=1] Roughness factor in range ````[0..1]````. Overridden by texture set ````metallicRoughnessTexture````.
2728
- * @returns {SceneModelMesh} The new mesh.
2727
+ * @returns {Boolean} True = successfully mesh was created. False = error during creation of a mesh.
2729
2728
  */
2730
2729
  createMesh(cfg) {
2731
2730
 
2732
2731
  if (cfg.id === undefined || cfg.id === null) {
2733
2732
  this.error("[createMesh] SceneModel.createMesh() config missing: id");
2734
- return;
2733
+ return false;
2735
2734
  }
2736
2735
 
2737
2736
  if (this._scheduledMeshes[cfg.id]) {
2738
2737
  this.error(`[createMesh] SceneModel already has a mesh with this ID: ${cfg.id}`);
2739
- return;
2738
+ return false;
2740
2739
  }
2741
2740
 
2742
2741
  const instancing = (cfg.geometryId !== undefined);
@@ -2751,31 +2750,31 @@ export class SceneModel extends Component {
2751
2750
  }
2752
2751
  if (cfg.primitive !== "points" && cfg.primitive !== "lines" && cfg.primitive !== "triangles" && cfg.primitive !== "solid" && cfg.primitive !== "surface") {
2753
2752
  this.error(`Unsupported value for 'primitive': '${primitive}' ('geometryId' is absent) - supported values are 'points', 'lines', 'triangles', 'solid' and 'surface'.`);
2754
- return;
2753
+ return false;
2755
2754
  }
2756
2755
  if (!cfg.positions && !cfg.positionsCompressed && !cfg.buckets) {
2757
2756
  this.error("Param expected: 'positions', 'positionsCompressed' or `buckets` ('geometryId' is absent)");
2758
- return null;
2757
+ return false;
2759
2758
  }
2760
2759
  if (cfg.positions && (cfg.positionsDecodeMatrix || cfg.positionsDecodeBoundary)) {
2761
2760
  this.error("Illegal params: 'positions' not expected with 'positionsDecodeMatrix'/'positionsDecodeBoundary' ('geometryId' is absent)");
2762
- return null;
2761
+ return false;
2763
2762
  }
2764
2763
  if (cfg.positionsCompressed && !cfg.positionsDecodeMatrix && !cfg.positionsDecodeBoundary) {
2765
2764
  this.error("Param expected: 'positionsCompressed' should be accompanied by 'positionsDecodeMatrix'/'positionsDecodeBoundary' ('geometryId' is absent)");
2766
- return null;
2765
+ return false;
2767
2766
  }
2768
2767
  if (cfg.uvCompressed && !cfg.uvDecodeMatrix) {
2769
2768
  this.error("Param expected: 'uvCompressed' should be accompanied by `uvDecodeMatrix` ('geometryId' is absent)");
2770
- return null;
2769
+ return false;
2771
2770
  }
2772
2771
  if (!cfg.buckets && !cfg.indices && cfg.primitive !== "points") {
2773
2772
  this.error(`Param expected: indices (required for '${cfg.primitive}' primitive type)`);
2774
- return null;
2773
+ return false;
2775
2774
  }
2776
2775
  if ((cfg.matrix || cfg.position || cfg.rotation || cfg.scale) && (cfg.positionsCompressed || cfg.positionsDecodeBoundary)) {
2777
2776
  this.error("Unexpected params: 'matrix', 'rotation', 'scale', 'position' not allowed with 'positionsCompressed'");
2778
- return null;
2777
+ return false;
2779
2778
  }
2780
2779
 
2781
2780
  const useDTX = (!!this._dtxEnabled && (cfg.primitive === "triangles"
@@ -2940,7 +2939,7 @@ export class SceneModel extends Component {
2940
2939
  cfg.textureSet = this._textureSets[cfg.textureSetId];
2941
2940
  if (!cfg.textureSet) {
2942
2941
  this.error(`[createMesh] Texture set not found: ${cfg.textureSetId} - ensure that you create it first with createTextureSet()`);
2943
- return;
2942
+ return false;
2944
2943
  }
2945
2944
  }
2946
2945
  }
@@ -2951,13 +2950,13 @@ export class SceneModel extends Component {
2951
2950
 
2952
2951
  if (cfg.positions || cfg.positionsCompressed || cfg.indices || cfg.edgeIndices || cfg.normals || cfg.normalsCompressed || cfg.uv || cfg.uvCompressed || cfg.positionsDecodeMatrix) {
2953
2952
  this.error(`Mesh geometry parameters not expected when instancing a geometry (not expected: positions, positionsCompressed, indices, edgeIndices, normals, normalsCompressed, uv, uvCompressed, positionsDecodeMatrix)`);
2954
- return;
2953
+ return false;
2955
2954
  }
2956
2955
 
2957
2956
  cfg.geometry = this._geometries[cfg.geometryId];
2958
2957
  if (!cfg.geometry) {
2959
2958
  this.error(`[createMesh] Geometry not found: ${cfg.geometryId} - ensure that you create it first with createGeometry()`);
2960
- return;
2959
+ return false;
2961
2960
  }
2962
2961
 
2963
2962
  cfg.origin = cfg.origin ? math.addVec3(this._origin, cfg.origin, math.vec3()) : this._origin;
@@ -2971,7 +2970,7 @@ export class SceneModel extends Component {
2971
2970
 
2972
2971
  if (!cfg.transform) {
2973
2972
  this.error(`[createMesh] Transform not found: ${cfg.transformId} - ensure that you create it first with createTransform()`);
2974
- return;
2973
+ return false;
2975
2974
  }
2976
2975
 
2977
2976
  cfg.aabb = cfg.geometry.aabb;
@@ -3039,7 +3038,7 @@ export class SceneModel extends Component {
3039
3038
  cfg.textureSet = this._textureSets[cfg.textureSetId];
3040
3039
  // if (!cfg.textureSet) {
3041
3040
  // this.error(`[createMesh] Texture set not found: ${cfg.textureSetId} - ensure that you create it first with createTextureSet()`);
3042
- // return;
3041
+ // return false;
3043
3042
  // }
3044
3043
  }
3045
3044
  }
@@ -3047,7 +3046,9 @@ export class SceneModel extends Component {
3047
3046
 
3048
3047
  cfg.numPrimitives = this._getNumPrimitives(cfg);
3049
3048
 
3050
- return this._createMesh(cfg);
3049
+ this._meshesCfgsBeforeMeshCreation[cfg.id] = cfg;
3050
+
3051
+ return true;
3051
3052
  }
3052
3053
 
3053
3054
  _createMesh(cfg) {
@@ -3079,8 +3080,6 @@ export class SceneModel extends Component {
3079
3080
  cfg.meshMatrix = cfg.transform.worldMatrix;
3080
3081
  }
3081
3082
  mesh.portionId = mesh.layer.createPortion(mesh, cfg);
3082
- this._meshes[cfg.id] = mesh;
3083
- this._meshList.push(mesh);
3084
3083
  return mesh;
3085
3084
  }
3086
3085
 
@@ -3439,10 +3438,15 @@ export class SceneModel extends Component {
3439
3438
  let meshes = [];
3440
3439
  for (let i = 0, len = cfg.meshIds.length; i < len; i++) {
3441
3440
  const meshId = cfg.meshIds[i];
3442
- const mesh = this._meshes[meshId];
3443
- if (!mesh) {
3444
- this.error(`Mesh with this ID not found: "${meshId}" - ignoring this mesh`);
3445
- continue;
3441
+ let mesh = this._meshes[meshId]; // Trying to get already created mesh
3442
+ if (!mesh) { // Checks if there is already created mesh for this meshId
3443
+ let meshCfg = this._meshesCfgsBeforeMeshCreation[meshId]; // Trying to get already created cfg
3444
+ if (!meshCfg) { // Checks if there is already created cfg for this meshId
3445
+ this.error(`Mesh with this ID not found: "${meshId}" - ignoring this mesh`); // There is no such cfg
3446
+ continue;
3447
+ }
3448
+ mesh = this._createMesh(meshCfg) // There is no such mesh yet, but there is already created cfg, so it creates this mesh
3449
+ this._meshes[cfg.id] = mesh; // Now it will also add this mesh to dictionary of created meshes
3446
3450
  }
3447
3451
  if (mesh.parent) {
3448
3452
  this.error(`Mesh with ID "${meshId}" already belongs to object with ID "${mesh.parent.id}" - ignoring this mesh`);
@@ -34,6 +34,8 @@ export declare type NavCubePluginConfiguration = {
34
34
  bottomColor?: string;
35
35
  /** Custom color for highlighting regions on the NavCube as we hover the pointer over them. */
36
36
  hoverColor?: string;
37
+ /** Custom text color for labels of the NavCube. */
38
+ textColor?: string;
37
39
  /** Sets whether the axis, corner and edge-aligned views will fit the view to the entire {@link Scene} or just to visible object-{@link Entity}s. Entitys are visible objects when {@link Entity.isObject} and {@link Entity.visible} are both ````true````. */
38
40
  fitVisible?: boolean;
39
41
  /** Sets whether the NavCube switches between perspective and orthographic projections in synchrony with the {@link Camera}. When ````false````, the NavCube will always be rendered with perspective projection. */