super-three 0.136.1 → 0.137.0

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 (100) hide show
  1. package/README.md +1 -1
  2. package/build/three.cjs +37132 -0
  3. package/build/three.js +71 -53
  4. package/build/three.min.js +2 -2
  5. package/build/three.module.js +80 -47
  6. package/examples/js/animation/MMDAnimationHelper.js +3 -1
  7. package/examples/js/controls/experimental/CameraControls.js +6 -2
  8. package/examples/js/exporters/GLTFExporter.js +82 -39
  9. package/examples/js/geometries/TextGeometry.js +12 -10
  10. package/examples/js/interactive/HTMLMesh.js +14 -2
  11. package/examples/js/loaders/EXRLoader.js +20 -9
  12. package/examples/js/loaders/GLTFLoader.js +1 -1
  13. package/examples/js/loaders/LDrawLoader.js +541 -425
  14. package/examples/js/loaders/MD2Loader.js +5 -5
  15. package/examples/js/loaders/MTLLoader.js +10 -3
  16. package/examples/js/loaders/PCDLoader.js +2 -2
  17. package/examples/js/loaders/STLLoader.js +1 -1
  18. package/examples/js/loaders/SVGLoader.js +3 -2
  19. package/examples/js/modifiers/EdgeSplitModifier.js +0 -6
  20. package/examples/js/modifiers/SimplifyModifier.js +0 -10
  21. package/examples/js/objects/Lensflare.js +2 -2
  22. package/examples/js/postprocessing/OutlinePass.js +1 -5
  23. package/examples/js/renderers/CSS2DRenderer.js +25 -19
  24. package/examples/js/renderers/CSS3DRenderer.js +37 -32
  25. package/examples/js/utils/LDrawUtils.js +182 -0
  26. package/examples/jsm/exporters/GLTFExporter.js +80 -12
  27. package/examples/jsm/geometries/TextGeometry.js +13 -13
  28. package/examples/jsm/interactive/HTMLMesh.js +16 -2
  29. package/examples/jsm/libs/flow.module.js +930 -169
  30. package/examples/jsm/loaders/EXRLoader.js +19 -9
  31. package/examples/jsm/loaders/GLTFLoader.js +1 -1
  32. package/examples/jsm/loaders/LDrawLoader.js +534 -442
  33. package/examples/jsm/loaders/MD2Loader.js +5 -5
  34. package/examples/jsm/loaders/MTLLoader.js +11 -4
  35. package/examples/jsm/loaders/PCDLoader.js +2 -2
  36. package/examples/jsm/loaders/STLLoader.js +1 -1
  37. package/examples/jsm/loaders/SVGLoader.js +3 -1
  38. package/examples/jsm/loaders/VRMLLoader.js +0 -1
  39. package/examples/jsm/modifiers/EdgeSplitModifier.js +0 -6
  40. package/examples/jsm/modifiers/SimplifyModifier.js +0 -10
  41. package/examples/jsm/node-editor/NodeEditor.js +435 -181
  42. package/examples/jsm/node-editor/accessors/NormalEditor.js +8 -8
  43. package/examples/jsm/node-editor/accessors/PositionEditor.js +8 -8
  44. package/examples/jsm/node-editor/accessors/UVEditor.js +6 -7
  45. package/examples/jsm/node-editor/core/BaseNode.js +83 -0
  46. package/examples/jsm/node-editor/display/BlendEditor.js +7 -6
  47. package/examples/jsm/node-editor/examples/animate-uv.json +1 -1
  48. package/examples/jsm/node-editor/examples/fake-top-light.json +1 -1
  49. package/examples/jsm/node-editor/examples/oscillator-color.json +1 -1
  50. package/examples/jsm/node-editor/examples/rim.json +1 -1
  51. package/examples/jsm/node-editor/inputs/ColorEditor.js +14 -10
  52. package/examples/jsm/node-editor/inputs/FloatEditor.js +6 -7
  53. package/examples/jsm/node-editor/inputs/SliderEditor.js +4 -5
  54. package/examples/jsm/node-editor/inputs/Vector2Editor.js +6 -7
  55. package/examples/jsm/node-editor/inputs/Vector3Editor.js +8 -9
  56. package/examples/jsm/node-editor/inputs/Vector4Editor.js +9 -10
  57. package/examples/jsm/node-editor/materials/BasicMaterialEditor.js +87 -0
  58. package/examples/jsm/node-editor/materials/PointsMaterialEditor.js +97 -0
  59. package/examples/jsm/node-editor/materials/StandardMaterialEditor.js +20 -17
  60. package/examples/jsm/node-editor/math/AngleEditor.js +39 -0
  61. package/examples/jsm/node-editor/math/DotEditor.js +6 -7
  62. package/examples/jsm/node-editor/math/InvertEditor.js +4 -3
  63. package/examples/jsm/node-editor/math/LimiterEditor.js +11 -10
  64. package/examples/jsm/node-editor/math/NormalizeEditor.js +6 -5
  65. package/examples/jsm/node-editor/math/OperatorEditor.js +12 -11
  66. package/examples/jsm/node-editor/math/PowerEditor.js +6 -5
  67. package/examples/jsm/node-editor/math/TrigonometryEditor.js +12 -7
  68. package/examples/jsm/node-editor/procedural/CheckerEditor.js +4 -3
  69. package/examples/jsm/node-editor/scene/MeshEditor.js +99 -0
  70. package/examples/jsm/node-editor/scene/Object3DEditor.js +160 -0
  71. package/examples/jsm/node-editor/scene/PointsEditor.js +99 -0
  72. package/examples/jsm/node-editor/utils/JoinEditor.js +58 -0
  73. package/examples/jsm/node-editor/utils/OscillatorEditor.js +7 -6
  74. package/examples/jsm/node-editor/utils/SplitEditor.js +39 -0
  75. package/examples/jsm/node-editor/utils/TimerEditor.js +6 -5
  76. package/examples/jsm/postprocessing/OutlinePass.js +1 -4
  77. package/examples/jsm/renderers/CSS2DRenderer.js +24 -19
  78. package/examples/jsm/renderers/CSS3DRenderer.js +36 -30
  79. package/examples/jsm/renderers/nodes/accessors/UVNode.js +4 -4
  80. package/examples/jsm/renderers/nodes/core/NodeBuilder.js +2 -1
  81. package/examples/jsm/renderers/nodes/utils/SplitNode.js +19 -4
  82. package/examples/jsm/utils/LDrawUtils.js +18 -11
  83. package/package.json +16 -9
  84. package/src/constants.js +1 -3
  85. package/src/core/BufferGeometry.js +2 -2
  86. package/src/geometries/LatheGeometry.js +1 -1
  87. package/src/loaders/FileLoader.js +20 -3
  88. package/src/math/Box3.js +24 -10
  89. package/src/renderers/WebGLRenderTarget.js +4 -1
  90. package/src/renderers/WebGLRenderer.js +3 -3
  91. package/src/renderers/shaders/ShaderChunk/morphnormal_vertex.glsl.js +1 -1
  92. package/src/renderers/shaders/ShaderChunk/morphtarget_vertex.glsl.js +2 -2
  93. package/src/renderers/webgl/WebGLBackground.js +2 -2
  94. package/src/renderers/webgl/WebGLGeometries.js +2 -2
  95. package/src/renderers/webgl/WebGLPrograms.js +2 -2
  96. package/src/renderers/webgl/WebGLState.js +2 -2
  97. package/src/renderers/webgl/WebGLTextures.js +9 -6
  98. package/src/renderers/webgl/WebGLUtils.js +1 -3
  99. package/src/renderers/webxr/WebXRManager.js +2 -0
  100. package/src/utils.js +15 -1
@@ -17,6 +17,8 @@
17
17
  const FILE_LOCATION_TRY_RELATIVE = 4;
18
18
  const FILE_LOCATION_TRY_ABSOLUTE = 5;
19
19
  const FILE_LOCATION_NOT_FOUND = 6;
20
+ const MAIN_COLOUR_CODE = '16';
21
+ const MAIN_EDGE_COLOUR_CODE = '24';
20
22
 
21
23
  const _tempVec0 = new THREE.Vector3();
22
24
 
@@ -142,6 +144,17 @@
142
144
 
143
145
  }
144
146
 
147
+ class ConditionalLineSegments extends THREE.LineSegments {
148
+
149
+ constructor( geometry, material ) {
150
+
151
+ super( geometry, material );
152
+ this.isConditionalLine = true;
153
+
154
+ }
155
+
156
+ }
157
+
145
158
  function generateFaceNormals( faces ) {
146
159
 
147
160
  for ( let i = 0, l = faces.length; i < l; i ++ ) {
@@ -497,13 +510,7 @@
497
510
 
498
511
  function isPartType( type ) {
499
512
 
500
- return type === 'Part';
501
-
502
- }
503
-
504
- function isModelType( type ) {
505
-
506
- return type === 'Model' || type === 'Unofficial_Model';
513
+ return type === 'Part' || type === 'Unofficial_Part';
507
514
 
508
515
  }
509
516
 
@@ -597,14 +604,15 @@
597
604
 
598
605
  }
599
606
 
600
- }
607
+ } // Fetches and parses an intermediate representation of LDraw parts files.
608
+
601
609
 
602
610
  class LDrawParsedCache {
603
611
 
604
612
  constructor( loader ) {
605
613
 
606
614
  this.loader = loader;
607
- this.cache = {};
615
+ this._cache = {};
608
616
 
609
617
  }
610
618
 
@@ -651,6 +659,7 @@
651
659
  result.totalFaces = original.totalFaces;
652
660
  result.startingConstructionStep = original.startingConstructionStep;
653
661
  result.materials = original.materials;
662
+ result.group = null;
654
663
  return result;
655
664
 
656
665
  }
@@ -733,7 +742,7 @@
733
742
 
734
743
  }
735
744
 
736
- parse( text ) {
745
+ parse( text, fileName = null ) {
737
746
 
738
747
  const loader = this.loader; // final results
739
748
 
@@ -745,7 +754,7 @@
745
754
 
746
755
  const getLocalMaterial = colorCode => {
747
756
 
748
- return colorCode in materials ? materials[ colorCode ] : null;
757
+ return materials[ colorCode ] || null;
749
758
 
750
759
  };
751
760
 
@@ -1135,37 +1144,376 @@
1135
1144
  subobjects,
1136
1145
  totalFaces,
1137
1146
  startingConstructionStep,
1138
- materials
1147
+ materials,
1148
+ fileName,
1149
+ group: null
1139
1150
  };
1140
1151
 
1141
- }
1152
+ } // returns an (optionally cloned) instance of the data
1142
1153
 
1143
- loadData( fileName ) {
1154
+
1155
+ getData( fileName, clone = true ) {
1144
1156
 
1145
1157
  const key = fileName.toLowerCase();
1158
+ const result = this._cache[ key ];
1159
+
1160
+ if ( result === null || result instanceof Promise ) {
1161
+
1162
+ return null;
1163
+
1164
+ }
1165
+
1166
+ if ( clone ) {
1167
+
1168
+ return this.cloneResult( result );
1169
+
1170
+ } else {
1146
1171
 
1147
- if ( ! ( key in this.cache ) ) {
1172
+ return result;
1148
1173
 
1149
- this.cache[ key ] = this.fetchData( fileName ).then( text => {
1174
+ }
1150
1175
 
1151
- return this.parse( text );
1176
+ } // kicks off a fetch and parse of the requested data if it hasn't already been loaded. Returns when
1177
+ // the data is ready to use and can be retrieved synchronously with "getData".
1178
+
1179
+
1180
+ async ensureDataLoaded( fileName ) {
1181
+
1182
+ const key = fileName.toLowerCase();
1183
+
1184
+ if ( ! ( key in this._cache ) ) {
1185
+
1186
+ // replace the promise with a copy of the parsed data for immediate processing
1187
+ this._cache[ key ] = this.fetchData( fileName ).then( text => {
1188
+
1189
+ const info = this.parse( text, fileName );
1190
+ this._cache[ key ] = info;
1191
+ return info;
1152
1192
 
1153
1193
  } );
1154
1194
 
1155
1195
  }
1156
1196
 
1157
- return this.cache[ key ].then( result => {
1197
+ await this._cache[ key ];
1158
1198
 
1159
- return this.cloneResult( result );
1199
+ } // sets the data in the cache from parsed data
1160
1200
 
1161
- } );
1201
+
1202
+ setData( fileName, text ) {
1203
+
1204
+ const key = fileName.toLowerCase();
1205
+ this._cache[ key ] = this.parse( text, fileName );
1162
1206
 
1163
1207
  }
1164
1208
 
1165
- setData( fileName, text ) {
1209
+ } // returns the material for an associated color code. If the color code is 16 for a face or 24 for
1210
+ // an edge then the passthroughColorCode is used.
1211
+
1212
+
1213
+ function getMaterialFromCode( colorCode, parentColorCode, materialHierarchy, forEdge ) {
1214
+
1215
+ const isPassthrough = ! forEdge && colorCode === MAIN_COLOUR_CODE || forEdge && colorCode === MAIN_EDGE_COLOUR_CODE;
1216
+
1217
+ if ( isPassthrough ) {
1218
+
1219
+ colorCode = parentColorCode;
1220
+
1221
+ }
1222
+
1223
+ return materialHierarchy[ colorCode ] || null;
1224
+
1225
+ } // Class used to parse and build LDraw parts as three.js objects and cache them if they're a "Part" type.
1226
+
1227
+
1228
+ class LDrawPartsGeometryCache {
1229
+
1230
+ constructor( loader ) {
1231
+
1232
+ this.loader = loader;
1233
+ this.parseCache = new LDrawParsedCache( loader );
1234
+ this._cache = {};
1235
+
1236
+ } // Convert the given file information into a mesh by processing subobjects.
1237
+
1238
+
1239
+ async processIntoMesh( info ) {
1240
+
1241
+ const loader = this.loader;
1242
+ const parseCache = this.parseCache;
1243
+ const faceMaterials = new Set(); // Processes the part subobject information to load child parts and merge geometry onto part
1244
+ // piece object.
1245
+
1246
+ const processInfoSubobjects = async ( info, subobject = null ) => {
1247
+
1248
+ const subobjects = info.subobjects;
1249
+ const promises = []; // Trigger load of all subobjects. If a subobject isn't a primitive then load it as a separate
1250
+ // group which lets instruction steps apply correctly.
1251
+
1252
+ for ( let i = 0, l = subobjects.length; i < l; i ++ ) {
1253
+
1254
+ const subobject = subobjects[ i ];
1255
+ const promise = parseCache.ensureDataLoaded( subobject.fileName ).then( () => {
1256
+
1257
+ const subobjectInfo = parseCache.getData( subobject.fileName, false );
1258
+
1259
+ if ( ! isPrimitiveType( subobjectInfo.type ) ) {
1260
+
1261
+ return this.loadModel( subobject.fileName ).catch( error => {
1262
+
1263
+ console.warn( error );
1264
+ return null;
1265
+
1266
+ } );
1267
+
1268
+ }
1269
+
1270
+ return processInfoSubobjects( parseCache.getData( subobject.fileName ), subobject );
1271
+
1272
+ } );
1273
+ promises.push( promise );
1274
+
1275
+ }
1276
+
1277
+ const group = new THREE.Group();
1278
+ group.userData.category = info.category;
1279
+ group.userData.keywords = info.keywords;
1280
+ info.group = group;
1281
+ const subobjectInfos = await Promise.all( promises );
1282
+
1283
+ for ( let i = 0, l = subobjectInfos.length; i < l; i ++ ) {
1284
+
1285
+ const subobject = info.subobjects[ i ];
1286
+ const subobjectInfo = subobjectInfos[ i ];
1287
+
1288
+ if ( subobjectInfo === null ) {
1289
+
1290
+ // the subobject failed to load
1291
+ continue;
1292
+
1293
+ } // if the subobject was loaded as a separate group then apply the parent scopes materials
1294
+
1295
+
1296
+ if ( subobjectInfo.isGroup ) {
1297
+
1298
+ const subobjectGroup = subobjectInfo;
1299
+ subobject.matrix.decompose( subobjectGroup.position, subobjectGroup.quaternion, subobjectGroup.scale );
1300
+ subobjectGroup.userData.startingConstructionStep = subobject.startingConstructionStep;
1301
+ subobjectGroup.name = subobject.fileName;
1302
+ loader.applyMaterialsToMesh( subobjectGroup, subobject.colorCode, info.materials );
1303
+ group.add( subobjectGroup );
1304
+ continue;
1305
+
1306
+ } // add the subobject group if it has children in case it has both children and primitives
1307
+
1308
+
1309
+ if ( subobjectInfo.group.children.length ) {
1310
+
1311
+ group.add( subobjectInfo.group );
1312
+
1313
+ } // transform the primitives into the local space of the parent piece and append them to
1314
+ // to the parent primitives list.
1315
+
1316
+
1317
+ const parentLineSegments = info.lineSegments;
1318
+ const parentConditionalSegments = info.conditionalSegments;
1319
+ const parentFaces = info.faces;
1320
+ const lineSegments = subobjectInfo.lineSegments;
1321
+ const conditionalSegments = subobjectInfo.conditionalSegments;
1322
+ const faces = subobjectInfo.faces;
1323
+ const matrix = subobject.matrix;
1324
+ const inverted = subobject.inverted;
1325
+ const matrixScaleInverted = matrix.determinant() < 0;
1326
+ const colorCode = subobject.colorCode;
1327
+ const lineColorCode = colorCode === MAIN_COLOUR_CODE ? MAIN_EDGE_COLOUR_CODE : colorCode;
1328
+
1329
+ for ( let i = 0, l = lineSegments.length; i < l; i ++ ) {
1330
+
1331
+ const ls = lineSegments[ i ];
1332
+ const vertices = ls.vertices;
1333
+ vertices[ 0 ].applyMatrix4( matrix );
1334
+ vertices[ 1 ].applyMatrix4( matrix );
1335
+ ls.colorCode = ls.colorCode === MAIN_EDGE_COLOUR_CODE ? lineColorCode : ls.colorCode;
1336
+ ls.material = ls.material || getMaterialFromCode( ls.colorCode, ls.colorCode, info.materials, true );
1337
+ parentLineSegments.push( ls );
1338
+
1339
+ }
1340
+
1341
+ for ( let i = 0, l = conditionalSegments.length; i < l; i ++ ) {
1342
+
1343
+ const os = conditionalSegments[ i ];
1344
+ const vertices = os.vertices;
1345
+ const controlPoints = os.controlPoints;
1346
+ vertices[ 0 ].applyMatrix4( matrix );
1347
+ vertices[ 1 ].applyMatrix4( matrix );
1348
+ controlPoints[ 0 ].applyMatrix4( matrix );
1349
+ controlPoints[ 1 ].applyMatrix4( matrix );
1350
+ os.colorCode = os.colorCode === MAIN_EDGE_COLOUR_CODE ? lineColorCode : os.colorCode;
1351
+ os.material = os.material || getMaterialFromCode( os.colorCode, os.colorCode, info.materials, true );
1352
+ parentConditionalSegments.push( os );
1353
+
1354
+ }
1355
+
1356
+ for ( let i = 0, l = faces.length; i < l; i ++ ) {
1357
+
1358
+ const tri = faces[ i ];
1359
+ const vertices = tri.vertices;
1360
+
1361
+ for ( let i = 0, l = vertices.length; i < l; i ++ ) {
1362
+
1363
+ vertices[ i ].applyMatrix4( matrix );
1364
+
1365
+ }
1366
+
1367
+ tri.colorCode = tri.colorCode === MAIN_COLOUR_CODE ? colorCode : tri.colorCode;
1368
+ tri.material = tri.material || getMaterialFromCode( tri.colorCode, colorCode, info.materials, false );
1369
+ faceMaterials.add( tri.colorCode ); // If the scale of the object is negated then the triangle winding order
1370
+ // needs to be flipped.
1371
+
1372
+ if ( matrixScaleInverted !== inverted ) {
1373
+
1374
+ vertices.reverse();
1375
+
1376
+ }
1166
1377
 
1378
+ parentFaces.push( tri );
1379
+
1380
+ }
1381
+
1382
+ info.totalFaces += subobjectInfo.totalFaces;
1383
+
1384
+ } // Apply the parent subobjects pass through material code to this object. This is done several times due
1385
+ // to material scoping.
1386
+
1387
+
1388
+ if ( subobject ) {
1389
+
1390
+ loader.applyMaterialsToMesh( group, subobject.colorCode, info.materials );
1391
+
1392
+ }
1393
+
1394
+ return info;
1395
+
1396
+ }; // Track material use to see if we need to use the normal smooth slow path for hard edges.
1397
+
1398
+
1399
+ for ( let i = 0, l = info.faces; i < l; i ++ ) {
1400
+
1401
+ faceMaterials.add( info.faces[ i ].colorCode );
1402
+
1403
+ }
1404
+
1405
+ await processInfoSubobjects( info );
1406
+
1407
+ if ( loader.smoothNormals ) {
1408
+
1409
+ const checkSubSegments = faceMaterials.size > 1;
1410
+ generateFaceNormals( info.faces );
1411
+ smoothNormals( info.faces, info.lineSegments, checkSubSegments );
1412
+
1413
+ } // Add the primitive objects and metadata.
1414
+
1415
+
1416
+ const group = info.group;
1417
+
1418
+ if ( info.faces.length > 0 ) {
1419
+
1420
+ group.add( createObject( info.faces, 3, false, info.totalFaces ) );
1421
+
1422
+ }
1423
+
1424
+ if ( info.lineSegments.length > 0 ) {
1425
+
1426
+ group.add( createObject( info.lineSegments, 2 ) );
1427
+
1428
+ }
1429
+
1430
+ if ( info.conditionalSegments.length > 0 ) {
1431
+
1432
+ group.add( createObject( info.conditionalSegments, 2, true ) );
1433
+
1434
+ }
1435
+
1436
+ return group;
1437
+
1438
+ }
1439
+
1440
+ hasCachedModel( fileName ) {
1441
+
1442
+ return fileName !== null && fileName.toLowerCase() in this._cache;
1443
+
1444
+ }
1445
+
1446
+ async getCachedModel( fileName ) {
1447
+
1448
+ if ( fileName !== null && this.hasCachedModel( fileName ) ) {
1449
+
1450
+ const key = fileName.toLowerCase();
1451
+ const group = await this._cache[ key ];
1452
+ return group.clone();
1453
+
1454
+ } else {
1455
+
1456
+ return null;
1457
+
1458
+ }
1459
+
1460
+ } // Loads and parses the model with the given file name. Returns a cached copy if available.
1461
+
1462
+
1463
+ async loadModel( fileName ) {
1464
+
1465
+ const parseCache = this.parseCache;
1167
1466
  const key = fileName.toLowerCase();
1168
- this.cache[ key ] = Promise.resolve( this.parse( text ) );
1467
+
1468
+ if ( this.hasCachedModel( fileName ) ) {
1469
+
1470
+ // Return cached model if available.
1471
+ return this.getCachedModel( fileName );
1472
+
1473
+ } else {
1474
+
1475
+ // Otherwise parse a new model.
1476
+ // Ensure the file data is loaded and pre parsed.
1477
+ await parseCache.ensureDataLoaded( fileName );
1478
+ const info = parseCache.getData( fileName );
1479
+ const promise = this.processIntoMesh( info ); // Now that the file has loaded it's possible that another part parse has been waiting in parallel
1480
+ // so check the cache again to see if it's been added since the last async operation so we don't
1481
+ // do unnecessary work.
1482
+
1483
+ if ( this.hasCachedModel( fileName ) ) {
1484
+
1485
+ return this.getCachedModel( fileName );
1486
+
1487
+ } // Cache object if it's a part so it can be reused later.
1488
+
1489
+
1490
+ if ( isPartType( info.type ) ) {
1491
+
1492
+ this._cache[ key ] = promise;
1493
+
1494
+ } // return a copy
1495
+
1496
+
1497
+ const group = await promise;
1498
+ return group.clone();
1499
+
1500
+ }
1501
+
1502
+ } // parses the given model text into a renderable object. Returns cached copy if available.
1503
+
1504
+
1505
+ async parseModel( text ) {
1506
+
1507
+ const parseCache = this.parseCache;
1508
+ const info = parseCache.parse( text );
1509
+
1510
+ if ( isPartType( info.type ) && this.hasCachedModel( info.fileName ) ) {
1511
+
1512
+ return this.getCachedModel( info.fileName );
1513
+
1514
+ }
1515
+
1516
+ return this.processIntoMesh( info );
1169
1517
 
1170
1518
  }
1171
1519
 
@@ -1290,7 +1638,7 @@
1290
1638
 
1291
1639
  }
1292
1640
 
1293
- if ( prevMaterial !== elem.material ) {
1641
+ if ( prevMaterial !== elem.colorCode ) {
1294
1642
 
1295
1643
  if ( prevMaterial !== null ) {
1296
1644
 
@@ -1300,25 +1648,43 @@
1300
1648
 
1301
1649
  const material = elem.material;
1302
1650
 
1303
- if ( elementSize === 3 ) {
1651
+ if ( material !== null ) {
1304
1652
 
1305
- materials.push( material );
1653
+ if ( elementSize === 3 ) {
1306
1654
 
1307
- } else if ( elementSize === 2 ) {
1655
+ materials.push( material );
1308
1656
 
1309
- if ( isConditionalSegments ) {
1657
+ } else if ( elementSize === 2 ) {
1310
1658
 
1311
- materials.push( material.userData.edgeMaterial.userData.conditionalEdgeMaterial );
1659
+ if ( material !== null ) {
1312
1660
 
1313
- } else {
1661
+ if ( isConditionalSegments ) {
1662
+
1663
+ materials.push( material.userData.edgeMaterial.userData.conditionalEdgeMaterial );
1664
+
1665
+ } else {
1314
1666
 
1315
- materials.push( material.userData.edgeMaterial );
1667
+ materials.push( material.userData.edgeMaterial );
1668
+
1669
+ }
1670
+
1671
+ } else {
1672
+
1673
+ materials.push( null );
1674
+
1675
+ }
1316
1676
 
1317
1677
  }
1318
1678
 
1679
+ } else {
1680
+
1681
+ // If a material has not been made available yet then keep the color code string in the material array
1682
+ // to save the spot for the material once a parent scopes materials are being applied to the object.
1683
+ materials.push( elem.colorCode );
1684
+
1319
1685
  }
1320
1686
 
1321
- prevMaterial = elem.material;
1687
+ prevMaterial = elem.colorCode;
1322
1688
  index0 = offset / 3;
1323
1689
  numGroupVerts = vertices.length;
1324
1690
 
@@ -1350,7 +1716,15 @@
1350
1716
 
1351
1717
  if ( elementSize === 2 ) {
1352
1718
 
1353
- object3d = new THREE.LineSegments( bufferGeometry, materials.length === 1 ? materials[ 0 ] : materials );
1719
+ if ( isConditionalSegments ) {
1720
+
1721
+ object3d = new ConditionalLineSegments( bufferGeometry, materials.length === 1 ? materials[ 0 ] : materials );
1722
+
1723
+ } else {
1724
+
1725
+ object3d = new THREE.LineSegments( bufferGeometry, materials.length === 1 ? materials[ 0 ] : materials );
1726
+
1727
+ }
1354
1728
 
1355
1729
  } else if ( elementSize === 3 ) {
1356
1730
 
@@ -1413,15 +1787,14 @@
1413
1787
 
1414
1788
  super( manager ); // Array of THREE.Material
1415
1789
 
1416
- this.materials = []; // Not using THREE.Cache here because it returns the previous HTML error response instead of calling onError()
1417
- // This also allows to handle the embedded text files ("0 FILE" lines)
1790
+ this.materials = [];
1791
+ this.materialLibrary = {}; // This also allows to handle the embedded text files ("0 FILE" lines)
1418
1792
 
1419
- this.parseCache = new LDrawParsedCache( this ); // This object is a map from file names to paths. It agilizes the paths search. If it is not set then files will be searched by trial and error.
1793
+ this.partsCache = new LDrawPartsGeometryCache( this ); // This object is a map from file names to paths. It agilizes the paths search. If it is not set then files will be searched by trial and error.
1420
1794
 
1421
- this.fileMap = {};
1422
- this.rootParseScope = this.newParseScopeLevel(); // Add default main triangle and line edge materials (used in pieces that can be colored with a main color)
1795
+ this.fileMap = {}; // Initializes the materials library with default materials
1423
1796
 
1424
- this.setMaterials( [ this.parseColorMetaDirective( new LineParser( 'Main_Colour CODE 16 VALUE #FF8080 EDGE #333333' ) ), this.parseColorMetaDirective( new LineParser( 'Edge_Colour CODE 24 VALUE #A0A0A0 EDGE #333333' ) ) ] ); // If this flag is set to true the vertex normals will be smoothed.
1797
+ this.setMaterials( [] ); // If this flag is set to true the vertex normals will be smoothed.
1425
1798
 
1426
1799
  this.smoothNormals = true; // The path to load parts from the LDraw parts library from.
1427
1800
 
@@ -1473,24 +1846,24 @@
1473
1846
  fileLoader.setWithCredentials( this.withCredentials );
1474
1847
  fileLoader.load( url, text => {
1475
1848
 
1476
- const parsedInfo = this.parseCache.parse( text );
1477
- this.processObject( parsedInfo, null, url, this.rootParseScope ).then( function ( result ) {
1849
+ this.partsCache.parseModel( text, this.materialLibrary ).then( group => {
1478
1850
 
1479
- onLoad( result.groupObject );
1851
+ this.applyMaterialsToMesh( group, MAIN_COLOUR_CODE, this.materialLibrary, true );
1852
+ this.computeConstructionSteps( group );
1853
+ onLoad( group );
1480
1854
 
1481
- } );
1855
+ } ).catch( onError );
1482
1856
 
1483
1857
  }, onProgress, onError );
1484
1858
 
1485
1859
  }
1486
1860
 
1487
- parse( text, path, onLoad ) {
1861
+ parse( text, onLoad ) {
1488
1862
 
1489
- // Async parse. This function calls onParse with the parsed THREE.Object3D as parameter
1490
- const parsedInfo = this.parseCache.parse( text );
1491
- this.processObject( parsedInfo, null, path, this.rootParseScope ).then( function ( result ) {
1863
+ this.partsCache.parseModel( text, this.materialLibrary ).then( group => {
1492
1864
 
1493
- onLoad( result.groupObject );
1865
+ this.computeConstructionSteps( group );
1866
+ onLoad( group );
1494
1867
 
1495
1868
  } );
1496
1869
 
@@ -1498,88 +1871,47 @@
1498
1871
 
1499
1872
  setMaterials( materials ) {
1500
1873
 
1501
- // Clears parse scopes stack, adds new scope with material library
1502
- this.rootParseScope = this.newParseScopeLevel( materials );
1503
- this.rootParseScope.isFromParse = false;
1504
- this.materials = materials;
1505
- return this;
1506
-
1507
- }
1508
-
1509
- setFileMap( fileMap ) {
1510
-
1511
- this.fileMap = fileMap;
1512
- return this;
1513
-
1514
- }
1874
+ this.materialLibrary = {};
1875
+ this.materials = [];
1515
1876
 
1516
- newParseScopeLevel( materials = null, parentScope = null ) {
1877
+ for ( let i = 0, l = materials.length; i < l; i ++ ) {
1517
1878
 
1518
- // Adds a new scope level, assign materials to it and returns it
1519
- const matLib = {};
1879
+ this.addMaterial( materials[ i ] );
1520
1880
 
1521
- if ( materials ) {
1881
+ } // Add default main triangle and line edge materials (used in pieces that can be colored with a main color)
1522
1882
 
1523
- for ( let i = 0, n = materials.length; i < n; i ++ ) {
1524
1883
 
1525
- const material = materials[ i ];
1526
- matLib[ material.userData.code ] = material;
1884
+ this.addMaterial( this.parseColorMetaDirective( new LineParser( 'Main_Colour CODE 16 VALUE #FF8080 EDGE #333333' ) ) );
1885
+ this.addMaterial( this.parseColorMetaDirective( new LineParser( 'Edge_Colour CODE 24 VALUE #A0A0A0 EDGE #333333' ) ) );
1886
+ return this;
1527
1887
 
1528
- }
1888
+ }
1529
1889
 
1530
- }
1890
+ setFileMap( fileMap ) {
1531
1891
 
1532
- const newParseScope = {
1533
- parentScope: parentScope,
1534
- lib: matLib,
1535
- url: null,
1536
- // Subobjects
1537
- subobjects: null,
1538
- numSubobjects: 0,
1539
- subobjectIndex: 0,
1540
- inverted: false,
1541
- category: null,
1542
- keywords: null,
1543
- // Current subobject
1544
- currentFileName: null,
1545
- mainColorCode: parentScope ? parentScope.mainColorCode : '16',
1546
- mainEdgeColorCode: parentScope ? parentScope.mainEdgeColorCode : '24',
1547
- matrix: new THREE.Matrix4(),
1548
- type: 'Model',
1549
- groupObject: null,
1550
- // If false, it is a root material scope previous to parse
1551
- isFromParse: true,
1552
- faces: [],
1553
- lineSegments: [],
1554
- conditionalSegments: [],
1555
- totalFaces: 0,
1556
- faceMaterials: new Set(),
1557
- // If true, this object is the start of a construction step
1558
- startingConstructionStep: false
1559
- };
1560
- return newParseScope;
1892
+ this.fileMap = fileMap;
1893
+ return this;
1561
1894
 
1562
1895
  }
1563
1896
 
1564
- addMaterial( material, parseScope ) {
1897
+ addMaterial( material ) {
1565
1898
 
1566
1899
  // Adds a material to the material library which is on top of the parse scopes stack. And also to the materials array
1567
- const matLib = parseScope.lib;
1900
+ const matLib = this.materialLibrary;
1568
1901
 
1569
1902
  if ( ! matLib[ material.userData.code ] ) {
1570
1903
 
1571
1904
  this.materials.push( material );
1905
+ matLib[ material.userData.code ] = material;
1572
1906
 
1573
1907
  }
1574
1908
 
1575
- matLib[ material.userData.code ] = material;
1576
1909
  return this;
1577
1910
 
1578
1911
  }
1579
1912
 
1580
- getMaterial( colorCode, parseScope = this.rootParseScope ) {
1913
+ getMaterial( colorCode ) {
1581
1914
 
1582
- // Given a color code search its material in the parse scopes stack
1583
1915
  if ( colorCode.startsWith( '0x2' ) ) {
1584
1916
 
1585
1917
  // Special 'direct' material value (RGB color)
@@ -1588,24 +1920,117 @@
1588
1920
 
1589
1921
  }
1590
1922
 
1591
- while ( parseScope ) {
1923
+ return this.materialLibrary[ colorCode ] || null;
1924
+
1925
+ } // Applies the appropriate materials to a prebuilt hierarchy of geometry. Assumes that color codes are present
1926
+ // in the material array if they need to be filled in.
1927
+
1928
+
1929
+ applyMaterialsToMesh( group, parentColorCode, materialHierarchy, finalMaterialPass = false ) {
1930
+
1931
+ // find any missing materials as indicated by a color code string and replace it with a material from the current material lib
1932
+ const loader = this;
1933
+ const parentIsPassthrough = parentColorCode === MAIN_COLOUR_CODE;
1934
+ group.traverse( c => {
1935
+
1936
+ if ( c.isMesh || c.isLineSegments ) {
1937
+
1938
+ if ( Array.isArray( c.material ) ) {
1939
+
1940
+ for ( let i = 0, l = c.material.length; i < l; i ++ ) {
1941
+
1942
+ if ( ! c.material[ i ].isMaterial ) {
1943
+
1944
+ c.material[ i ] = getMaterial( c, c.material[ i ] );
1945
+
1946
+ }
1947
+
1948
+ }
1949
+
1950
+ } else if ( ! c.material.isMaterial ) {
1951
+
1952
+ c.material = getMaterial( c, c.material );
1953
+
1954
+ }
1955
+
1956
+ }
1957
+
1958
+ } ); // Returns the appropriate material for the object (line or face) given color code. If the code is "pass through"
1959
+ // (24 for lines, 16 for edges) then the pass through color code is used. If that is also pass through then it's
1960
+ // simply returned for the subsequent material application.
1592
1961
 
1593
- const material = parseScope.lib[ colorCode ];
1962
+ function getMaterial( c, colorCode ) {
1594
1963
 
1595
- if ( material ) {
1964
+ // if our parent is a passthrough color code and we don't have the current material color available then
1965
+ // return early.
1966
+ if ( parentIsPassthrough && ! ( colorCode in materialHierarchy ) && ! finalMaterialPass ) {
1596
1967
 
1597
- return material;
1968
+ return colorCode;
1969
+
1970
+ }
1971
+
1972
+ const forEdge = c.isLineSegments || c.isConditionalLine;
1973
+ const isPassthrough = ! forEdge && colorCode === MAIN_COLOUR_CODE || forEdge && colorCode === MAIN_EDGE_COLOUR_CODE;
1974
+
1975
+ if ( isPassthrough ) {
1976
+
1977
+ colorCode = parentColorCode;
1978
+
1979
+ }
1980
+
1981
+ let material = null;
1982
+
1983
+ if ( colorCode in materialHierarchy ) {
1984
+
1985
+ material = materialHierarchy[ colorCode ];
1986
+
1987
+ } else if ( finalMaterialPass ) {
1988
+
1989
+ // see if we can get the final material from from the "getMaterial" function which will attempt to
1990
+ // parse the "direct" colors
1991
+ material = loader.getMaterial( colorCode );
1992
+
1993
+ if ( material === null ) {
1994
+
1995
+ // otherwise throw an error if this is final opportunity to set the material
1996
+ throw new Error( `LDrawLoader: Material properties for code ${colorCode} not available.` );
1997
+
1998
+ }
1598
1999
 
1599
2000
  } else {
1600
2001
 
1601
- parseScope = parseScope.parentScope;
2002
+ return colorCode;
1602
2003
 
1603
2004
  }
1604
2005
 
1605
- } // Material was not found
2006
+ if ( c.isLineSegments ) {
2007
+
2008
+ material = material.userData.edgeMaterial;
2009
+
2010
+ if ( c.isConditionalLine ) {
1606
2011
 
2012
+ material = material.userData.conditionalEdgeMaterial;
1607
2013
 
1608
- return null;
2014
+ }
2015
+
2016
+ }
2017
+
2018
+ return material;
2019
+
2020
+ }
2021
+
2022
+ }
2023
+
2024
+ getMainMaterial() {
2025
+
2026
+ return this.getMaterial( MAIN_COLOUR_CODE );
2027
+
2028
+ }
2029
+
2030
+ getMainEdgeMaterial() {
2031
+
2032
+ const mainMat = this.getMainMaterial();
2033
+ return mainMat && mainMat.userData ? mainMat.userData.edgeMaterial : null;
1609
2034
 
1610
2035
  }
1611
2036
 
@@ -1820,6 +2245,7 @@
1820
2245
  material.premultipliedAlpha = true;
1821
2246
  material.opacity = alpha;
1822
2247
  material.depthWrite = ! isTransparent;
2248
+ material.color.convertSRGBToLinear();
1823
2249
  material.polygonOffset = true;
1824
2250
  material.polygonOffsetFactor = 1;
1825
2251
 
@@ -1839,7 +2265,8 @@
1839
2265
  depthWrite: ! isTransparent
1840
2266
  } );
1841
2267
  edgeMaterial.userData.code = code;
1842
- edgeMaterial.name = name + ' - Edge'; // This is the material used for conditional edges
2268
+ edgeMaterial.name = name + ' - Edge';
2269
+ edgeMaterial.color.convertSRGBToLinear(); // This is the material used for conditional edges
1843
2270
 
1844
2271
  edgeMaterial.userData.conditionalEdgeMaterial = new LDrawConditionalLineMaterial( {
1845
2272
  fog: true,
@@ -1848,125 +2275,16 @@
1848
2275
  color: edgeColor,
1849
2276
  opacity: alpha
1850
2277
  } );
2278
+ edgeMaterial.userData.conditionalEdgeMaterial.color.convertSRGBToLinear();
1851
2279
 
1852
2280
  }
1853
2281
 
1854
2282
  material.userData.code = code;
1855
2283
  material.name = name;
1856
2284
  material.userData.edgeMaterial = edgeMaterial;
2285
+ this.addMaterial( material );
1857
2286
  return material;
1858
2287
 
1859
- } //
1860
-
1861
-
1862
- objectParse( info, parseScope ) {
1863
-
1864
- // Retrieve data from the parent parse scope
1865
- const currentParseScope = parseScope;
1866
- const parentParseScope = currentParseScope.parentScope; // Main color codes passed to this subobject (or default codes 16 and 24 if it is the root object)
1867
-
1868
- const mainColorCode = currentParseScope.mainColorCode;
1869
- const mainEdgeColorCode = currentParseScope.mainEdgeColorCode;
1870
-
1871
- const parseColorCode = ( colorCode, forEdge ) => {
1872
-
1873
- // Parses next color code and returns a THREE.Material
1874
- if ( ! forEdge && colorCode === '16' ) {
1875
-
1876
- colorCode = mainColorCode;
1877
-
1878
- }
1879
-
1880
- if ( forEdge && colorCode === '24' ) {
1881
-
1882
- colorCode = mainEdgeColorCode;
1883
-
1884
- }
1885
-
1886
- const material = this.getMaterial( colorCode, currentParseScope );
1887
-
1888
- if ( ! material ) {
1889
-
1890
- throw new Error( 'LDrawLoader: Unknown color code "' + colorCode + '" is used but it was not defined previously.' );
1891
-
1892
- }
1893
-
1894
- return material;
1895
-
1896
- };
1897
-
1898
- const faces = info.faces;
1899
- const lineSegments = info.lineSegments;
1900
- const conditionalSegments = info.conditionalSegments;
1901
- const materials = info.materials;
1902
-
1903
- if ( currentParseScope.inverted ) {
1904
-
1905
- faces.reverse();
1906
-
1907
- }
1908
-
1909
- for ( const colorCode in materials ) {
1910
-
1911
- this.addMaterial( materials[ colorCode ], currentParseScope );
1912
-
1913
- }
1914
-
1915
- for ( let i = 0, l = faces.length; i < l; i ++ ) {
1916
-
1917
- const face = faces[ i ];
1918
-
1919
- if ( face.material === null ) {
1920
-
1921
- face.material = parseColorCode( face.colorCode, false );
1922
-
1923
- }
1924
-
1925
- }
1926
-
1927
- for ( let i = 0, l = lineSegments.length; i < l; i ++ ) {
1928
-
1929
- const ls = lineSegments[ i ];
1930
-
1931
- if ( ls.material === null ) {
1932
-
1933
- ls.material = parseColorCode( ls.colorCode, true );
1934
-
1935
- }
1936
-
1937
- }
1938
-
1939
- for ( let i = 0, l = conditionalSegments.length; i < l; i ++ ) {
1940
-
1941
- const cs = conditionalSegments[ i ];
1942
-
1943
- if ( cs.material === null ) {
1944
-
1945
- cs.material = parseColorCode( cs.colorCode, true );
1946
-
1947
- }
1948
-
1949
- }
1950
-
1951
- currentParseScope.faces = info.faces;
1952
- currentParseScope.conditionalSegments = info.conditionalSegments;
1953
- currentParseScope.lineSegments = info.lineSegments;
1954
- currentParseScope.category = info.category;
1955
- currentParseScope.keywords = info.keywords;
1956
- currentParseScope.subobjects = info.subobjects;
1957
- currentParseScope.numSubobjects = info.subobjects.length;
1958
- currentParseScope.subobjectIndex = 0;
1959
- currentParseScope.type = info.type;
1960
- currentParseScope.totalFaces = info.totalFaces;
1961
- const isRoot = ! parentParseScope.isFromParse;
1962
-
1963
- if ( isRoot || ! isPrimitiveType( info.type ) ) {
1964
-
1965
- currentParseScope.groupObject = new THREE.Group();
1966
- currentParseScope.groupObject.userData.startingConstructionStep = currentParseScope.startingConstructionStep;
1967
-
1968
- }
1969
-
1970
2288
  }
1971
2289
 
1972
2290
  computeConstructionSteps( model ) {
@@ -1992,208 +2310,6 @@
1992
2310
 
1993
2311
  }
1994
2312
 
1995
- finalizeObject( subobjectParseScope ) {
1996
-
1997
- // fail gracefully if an object could not be loaded
1998
- if ( subobjectParseScope === null ) {
1999
-
2000
- return;
2001
-
2002
- }
2003
-
2004
- const parentParseScope = subobjectParseScope.parentScope; // Smooth the normals if this is a part or if this is a case where the subpart
2005
- // is added directly into the parent model (meaning it will never get smoothed by
2006
- // being added to a part)
2007
-
2008
- const doSmooth = isPartType( subobjectParseScope.type ) || isPrimitiveType( subobjectParseScope.type ) && isModelType( subobjectParseScope.parentScope.type );
2009
-
2010
- if ( this.smoothNormals && doSmooth ) {
2011
-
2012
- generateFaceNormals( subobjectParseScope.faces ); // only check subsetgments if we have multiple materials in a single part because this seems to be the case where it's needed most --
2013
- // there may be cases where a single edge line crosses over polygon edges that are broken up by multiple materials.
2014
-
2015
- const checkSubSegments = subobjectParseScope.faceMaterials.size > 1;
2016
- smoothNormals( subobjectParseScope.faces, subobjectParseScope.lineSegments, checkSubSegments );
2017
-
2018
- }
2019
-
2020
- const isRoot = ! parentParseScope.isFromParse;
2021
-
2022
- if ( ! isPrimitiveType( subobjectParseScope.type ) || isRoot ) {
2023
-
2024
- const objGroup = subobjectParseScope.groupObject;
2025
-
2026
- if ( subobjectParseScope.faces.length > 0 ) {
2027
-
2028
- objGroup.add( createObject( subobjectParseScope.faces, 3, false, subobjectParseScope.totalFaces ) );
2029
-
2030
- }
2031
-
2032
- if ( subobjectParseScope.lineSegments.length > 0 ) {
2033
-
2034
- objGroup.add( createObject( subobjectParseScope.lineSegments, 2 ) );
2035
-
2036
- }
2037
-
2038
- if ( subobjectParseScope.conditionalSegments.length > 0 ) {
2039
-
2040
- objGroup.add( createObject( subobjectParseScope.conditionalSegments, 2, true ) );
2041
-
2042
- }
2043
-
2044
- if ( parentParseScope.groupObject ) {
2045
-
2046
- objGroup.name = subobjectParseScope.fileName;
2047
- objGroup.userData.category = subobjectParseScope.category;
2048
- objGroup.userData.keywords = subobjectParseScope.keywords;
2049
- subobjectParseScope.matrix.decompose( objGroup.position, objGroup.quaternion, objGroup.scale );
2050
- parentParseScope.groupObject.add( objGroup );
2051
-
2052
- }
2053
-
2054
- } else {
2055
-
2056
- const parentLineSegments = parentParseScope.lineSegments;
2057
- const parentConditionalSegments = parentParseScope.conditionalSegments;
2058
- const parentFaces = parentParseScope.faces;
2059
- const parentFaceMaterials = parentParseScope.faceMaterials;
2060
- const lineSegments = subobjectParseScope.lineSegments;
2061
- const conditionalSegments = subobjectParseScope.conditionalSegments;
2062
- const faces = subobjectParseScope.faces;
2063
- const faceMaterials = subobjectParseScope.faceMaterials;
2064
- const matrix = subobjectParseScope.matrix;
2065
- const matrixScaleInverted = matrix.determinant() < 0;
2066
-
2067
- for ( let i = 0, l = lineSegments.length; i < l; i ++ ) {
2068
-
2069
- const ls = lineSegments[ i ];
2070
- const vertices = ls.vertices;
2071
- vertices[ 0 ].applyMatrix4( matrix );
2072
- vertices[ 1 ].applyMatrix4( matrix );
2073
- parentLineSegments.push( ls );
2074
-
2075
- }
2076
-
2077
- for ( let i = 0, l = conditionalSegments.length; i < l; i ++ ) {
2078
-
2079
- const os = conditionalSegments[ i ];
2080
- const vertices = os.vertices;
2081
- const controlPoints = os.controlPoints;
2082
- vertices[ 0 ].applyMatrix4( matrix );
2083
- vertices[ 1 ].applyMatrix4( matrix );
2084
- controlPoints[ 0 ].applyMatrix4( matrix );
2085
- controlPoints[ 1 ].applyMatrix4( matrix );
2086
- parentConditionalSegments.push( os );
2087
-
2088
- }
2089
-
2090
- for ( let i = 0, l = faces.length; i < l; i ++ ) {
2091
-
2092
- const tri = faces[ i ];
2093
- const vertices = tri.vertices;
2094
-
2095
- for ( let i = 0, l = vertices.length; i < l; i ++ ) {
2096
-
2097
- vertices[ i ].applyMatrix4( matrix );
2098
-
2099
- } // If the scale of the object is negated then the triangle winding order
2100
- // needs to be flipped.
2101
-
2102
-
2103
- if ( matrixScaleInverted !== subobjectParseScope.inverted ) {
2104
-
2105
- vertices.reverse();
2106
-
2107
- }
2108
-
2109
- parentFaces.push( tri );
2110
-
2111
- }
2112
-
2113
- parentParseScope.totalFaces += subobjectParseScope.totalFaces;
2114
- faceMaterials.forEach( material => parentFaceMaterials.add( material ) );
2115
-
2116
- }
2117
-
2118
- }
2119
-
2120
- async processObject( parsedInfo, subobject, url, parentScope ) {
2121
-
2122
- const scope = this;
2123
- const parseScope = this.newParseScopeLevel( null, parentScope );
2124
- parseScope.url = url;
2125
- const parentParseScope = parseScope.parentScope; // Set current matrix
2126
-
2127
- if ( subobject ) {
2128
-
2129
- parseScope.matrix.copy( subobject.matrix );
2130
- parseScope.inverted = subobject.inverted;
2131
- parseScope.startingConstructionStep = subobject.startingConstructionStep;
2132
- parseScope.fileName = subobject.fileName;
2133
-
2134
- if ( subobject.colorCode === '16' && parseScope.parentScope ) {
2135
-
2136
- const parentScope = parseScope.parentScope;
2137
- parseScope.mainColorCode = parentScope.mainColorCode;
2138
- parseScope.mainEdgeColorCode = parentScope.mainEdgeColorCode;
2139
-
2140
- } else if ( subobject.colorCode !== '16' ) {
2141
-
2142
- parseScope.mainColorCode = subobject.colorCode;
2143
- parseScope.mainEdgeColorCode = subobject.colorCode;
2144
-
2145
- }
2146
-
2147
- } // Parse the object
2148
-
2149
-
2150
- this.objectParse( parsedInfo, parseScope );
2151
- const subobjects = parseScope.subobjects;
2152
- const promises = [];
2153
-
2154
- for ( let i = 0, l = subobjects.length; i < l; i ++ ) {
2155
-
2156
- promises.push( loadSubobject( parseScope.subobjects[ i ] ) );
2157
-
2158
- } // Kick off of the downloads in parallel but process all the subobjects
2159
- // in order so all the assembly instructions are correct
2160
-
2161
-
2162
- const subobjectScopes = await Promise.all( promises );
2163
-
2164
- for ( let i = 0, l = subobjectScopes.length; i < l; i ++ ) {
2165
-
2166
- this.finalizeObject( subobjectScopes[ i ] );
2167
-
2168
- } // If it is root object then finalize this object and compute construction steps
2169
-
2170
-
2171
- if ( ! parentParseScope.isFromParse ) {
2172
-
2173
- this.finalizeObject( parseScope );
2174
- this.computeConstructionSteps( parseScope.groupObject );
2175
-
2176
- }
2177
-
2178
- return parseScope;
2179
-
2180
- function loadSubobject( subobject ) {
2181
-
2182
- return scope.parseCache.loadData( subobject.fileName ).then( function ( parsedInfo ) {
2183
-
2184
- return scope.processObject( parsedInfo, subobject, url, parseScope );
2185
-
2186
- } ).catch( function ( err ) {
2187
-
2188
- console.warn( err );
2189
- return null;
2190
-
2191
- } );
2192
-
2193
- }
2194
-
2195
- }
2196
-
2197
2313
  }
2198
2314
 
2199
2315
  THREE.LDrawLoader = LDrawLoader;