@2112-lab/central-plant 0.1.10 → 0.1.11
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.
- package/dist/bundle/index.js +1160 -34
- package/dist/cjs/node_modules/three/examples/jsm/loaders/OBJLoader.js +943 -0
- package/dist/cjs/src/rendering/modelPreloader.js +246 -35
- package/dist/esm/node_modules/three/examples/jsm/loaders/OBJLoader.js +939 -0
- package/dist/esm/src/rendering/modelPreloader.js +227 -36
- package/package.json +1 -1
package/dist/bundle/index.js
CHANGED
|
@@ -9231,16 +9231,953 @@ function addPrimitiveAttributes( geometry, primitiveDef, parser ) {
|
|
|
9231
9231
|
|
|
9232
9232
|
}
|
|
9233
9233
|
|
|
9234
|
+
// o object_name | g group_name
|
|
9235
|
+
const _object_pattern = /^[og]\s*(.+)?/;
|
|
9236
|
+
// mtllib file_reference
|
|
9237
|
+
const _material_library_pattern = /^mtllib /;
|
|
9238
|
+
// usemtl material_name
|
|
9239
|
+
const _material_use_pattern = /^usemtl /;
|
|
9240
|
+
// usemap map_name
|
|
9241
|
+
const _map_use_pattern = /^usemap /;
|
|
9242
|
+
const _face_vertex_data_separator_pattern = /\s+/;
|
|
9243
|
+
|
|
9244
|
+
const _vA = new THREE.Vector3();
|
|
9245
|
+
const _vB = new THREE.Vector3();
|
|
9246
|
+
const _vC = new THREE.Vector3();
|
|
9247
|
+
|
|
9248
|
+
const _ab = new THREE.Vector3();
|
|
9249
|
+
const _cb = new THREE.Vector3();
|
|
9250
|
+
|
|
9251
|
+
const _color = new THREE.Color();
|
|
9252
|
+
|
|
9253
|
+
function ParserState() {
|
|
9254
|
+
|
|
9255
|
+
const state = {
|
|
9256
|
+
objects: [],
|
|
9257
|
+
object: {},
|
|
9258
|
+
|
|
9259
|
+
vertices: [],
|
|
9260
|
+
normals: [],
|
|
9261
|
+
colors: [],
|
|
9262
|
+
uvs: [],
|
|
9263
|
+
|
|
9264
|
+
materials: {},
|
|
9265
|
+
materialLibraries: [],
|
|
9266
|
+
|
|
9267
|
+
startObject: function ( name, fromDeclaration ) {
|
|
9268
|
+
|
|
9269
|
+
// If the current object (initial from reset) is not from a g/o declaration in the parsed
|
|
9270
|
+
// file. We need to use it for the first parsed g/o to keep things in sync.
|
|
9271
|
+
if ( this.object && this.object.fromDeclaration === false ) {
|
|
9272
|
+
|
|
9273
|
+
this.object.name = name;
|
|
9274
|
+
this.object.fromDeclaration = ( fromDeclaration !== false );
|
|
9275
|
+
return;
|
|
9276
|
+
|
|
9277
|
+
}
|
|
9278
|
+
|
|
9279
|
+
const previousMaterial = ( this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined );
|
|
9280
|
+
|
|
9281
|
+
if ( this.object && typeof this.object._finalize === 'function' ) {
|
|
9282
|
+
|
|
9283
|
+
this.object._finalize( true );
|
|
9284
|
+
|
|
9285
|
+
}
|
|
9286
|
+
|
|
9287
|
+
this.object = {
|
|
9288
|
+
name: name || '',
|
|
9289
|
+
fromDeclaration: ( fromDeclaration !== false ),
|
|
9290
|
+
|
|
9291
|
+
geometry: {
|
|
9292
|
+
vertices: [],
|
|
9293
|
+
normals: [],
|
|
9294
|
+
colors: [],
|
|
9295
|
+
uvs: [],
|
|
9296
|
+
hasUVIndices: false
|
|
9297
|
+
},
|
|
9298
|
+
materials: [],
|
|
9299
|
+
smooth: true,
|
|
9300
|
+
|
|
9301
|
+
startMaterial: function ( name, libraries ) {
|
|
9302
|
+
|
|
9303
|
+
const previous = this._finalize( false );
|
|
9304
|
+
|
|
9305
|
+
// New usemtl declaration overwrites an inherited material, except if faces were declared
|
|
9306
|
+
// after the material, then it must be preserved for proper MultiMaterial continuation.
|
|
9307
|
+
if ( previous && ( previous.inherited || previous.groupCount <= 0 ) ) {
|
|
9308
|
+
|
|
9309
|
+
this.materials.splice( previous.index, 1 );
|
|
9310
|
+
|
|
9311
|
+
}
|
|
9312
|
+
|
|
9313
|
+
const material = {
|
|
9314
|
+
index: this.materials.length,
|
|
9315
|
+
name: name || '',
|
|
9316
|
+
mtllib: ( Array.isArray( libraries ) && libraries.length > 0 ? libraries[ libraries.length - 1 ] : '' ),
|
|
9317
|
+
smooth: ( previous !== undefined ? previous.smooth : this.smooth ),
|
|
9318
|
+
groupStart: ( previous !== undefined ? previous.groupEnd : 0 ),
|
|
9319
|
+
groupEnd: - 1,
|
|
9320
|
+
groupCount: - 1,
|
|
9321
|
+
inherited: false,
|
|
9322
|
+
|
|
9323
|
+
clone: function ( index ) {
|
|
9324
|
+
|
|
9325
|
+
const cloned = {
|
|
9326
|
+
index: ( typeof index === 'number' ? index : this.index ),
|
|
9327
|
+
name: this.name,
|
|
9328
|
+
mtllib: this.mtllib,
|
|
9329
|
+
smooth: this.smooth,
|
|
9330
|
+
groupStart: 0,
|
|
9331
|
+
groupEnd: - 1,
|
|
9332
|
+
groupCount: - 1,
|
|
9333
|
+
inherited: false
|
|
9334
|
+
};
|
|
9335
|
+
cloned.clone = this.clone.bind( cloned );
|
|
9336
|
+
return cloned;
|
|
9337
|
+
|
|
9338
|
+
}
|
|
9339
|
+
};
|
|
9340
|
+
|
|
9341
|
+
this.materials.push( material );
|
|
9342
|
+
|
|
9343
|
+
return material;
|
|
9344
|
+
|
|
9345
|
+
},
|
|
9346
|
+
|
|
9347
|
+
currentMaterial: function () {
|
|
9348
|
+
|
|
9349
|
+
if ( this.materials.length > 0 ) {
|
|
9350
|
+
|
|
9351
|
+
return this.materials[ this.materials.length - 1 ];
|
|
9352
|
+
|
|
9353
|
+
}
|
|
9354
|
+
|
|
9355
|
+
return undefined;
|
|
9356
|
+
|
|
9357
|
+
},
|
|
9358
|
+
|
|
9359
|
+
_finalize: function ( end ) {
|
|
9360
|
+
|
|
9361
|
+
const lastMultiMaterial = this.currentMaterial();
|
|
9362
|
+
if ( lastMultiMaterial && lastMultiMaterial.groupEnd === - 1 ) {
|
|
9363
|
+
|
|
9364
|
+
lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
|
|
9365
|
+
lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
|
|
9366
|
+
lastMultiMaterial.inherited = false;
|
|
9367
|
+
|
|
9368
|
+
}
|
|
9369
|
+
|
|
9370
|
+
// Ignore objects tail materials if no face declarations followed them before a new o/g started.
|
|
9371
|
+
if ( end && this.materials.length > 1 ) {
|
|
9372
|
+
|
|
9373
|
+
for ( let mi = this.materials.length - 1; mi >= 0; mi -- ) {
|
|
9374
|
+
|
|
9375
|
+
if ( this.materials[ mi ].groupCount <= 0 ) {
|
|
9376
|
+
|
|
9377
|
+
this.materials.splice( mi, 1 );
|
|
9378
|
+
|
|
9379
|
+
}
|
|
9380
|
+
|
|
9381
|
+
}
|
|
9382
|
+
|
|
9383
|
+
}
|
|
9384
|
+
|
|
9385
|
+
// Guarantee at least one empty material, this makes the creation later more straight forward.
|
|
9386
|
+
if ( end && this.materials.length === 0 ) {
|
|
9387
|
+
|
|
9388
|
+
this.materials.push( {
|
|
9389
|
+
name: '',
|
|
9390
|
+
smooth: this.smooth
|
|
9391
|
+
} );
|
|
9392
|
+
|
|
9393
|
+
}
|
|
9394
|
+
|
|
9395
|
+
return lastMultiMaterial;
|
|
9396
|
+
|
|
9397
|
+
}
|
|
9398
|
+
};
|
|
9399
|
+
|
|
9400
|
+
// Inherit previous objects material.
|
|
9401
|
+
// Spec tells us that a declared material must be set to all objects until a new material is declared.
|
|
9402
|
+
// If a usemtl declaration is encountered while this new object is being parsed, it will
|
|
9403
|
+
// overwrite the inherited material. Exception being that there was already face declarations
|
|
9404
|
+
// to the inherited material, then it will be preserved for proper MultiMaterial continuation.
|
|
9405
|
+
|
|
9406
|
+
if ( previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function' ) {
|
|
9407
|
+
|
|
9408
|
+
const declared = previousMaterial.clone( 0 );
|
|
9409
|
+
declared.inherited = true;
|
|
9410
|
+
this.object.materials.push( declared );
|
|
9411
|
+
|
|
9412
|
+
}
|
|
9413
|
+
|
|
9414
|
+
this.objects.push( this.object );
|
|
9415
|
+
|
|
9416
|
+
},
|
|
9417
|
+
|
|
9418
|
+
finalize: function () {
|
|
9419
|
+
|
|
9420
|
+
if ( this.object && typeof this.object._finalize === 'function' ) {
|
|
9421
|
+
|
|
9422
|
+
this.object._finalize( true );
|
|
9423
|
+
|
|
9424
|
+
}
|
|
9425
|
+
|
|
9426
|
+
},
|
|
9427
|
+
|
|
9428
|
+
parseVertexIndex: function ( value, len ) {
|
|
9429
|
+
|
|
9430
|
+
const index = parseInt( value, 10 );
|
|
9431
|
+
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
|
|
9432
|
+
|
|
9433
|
+
},
|
|
9434
|
+
|
|
9435
|
+
parseNormalIndex: function ( value, len ) {
|
|
9436
|
+
|
|
9437
|
+
const index = parseInt( value, 10 );
|
|
9438
|
+
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
|
|
9439
|
+
|
|
9440
|
+
},
|
|
9441
|
+
|
|
9442
|
+
parseUVIndex: function ( value, len ) {
|
|
9443
|
+
|
|
9444
|
+
const index = parseInt( value, 10 );
|
|
9445
|
+
return ( index >= 0 ? index - 1 : index + len / 2 ) * 2;
|
|
9446
|
+
|
|
9447
|
+
},
|
|
9448
|
+
|
|
9449
|
+
addVertex: function ( a, b, c ) {
|
|
9450
|
+
|
|
9451
|
+
const src = this.vertices;
|
|
9452
|
+
const dst = this.object.geometry.vertices;
|
|
9453
|
+
|
|
9454
|
+
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
|
9455
|
+
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
|
|
9456
|
+
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
|
|
9457
|
+
|
|
9458
|
+
},
|
|
9459
|
+
|
|
9460
|
+
addVertexPoint: function ( a ) {
|
|
9461
|
+
|
|
9462
|
+
const src = this.vertices;
|
|
9463
|
+
const dst = this.object.geometry.vertices;
|
|
9464
|
+
|
|
9465
|
+
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
|
9466
|
+
|
|
9467
|
+
},
|
|
9468
|
+
|
|
9469
|
+
addVertexLine: function ( a ) {
|
|
9470
|
+
|
|
9471
|
+
const src = this.vertices;
|
|
9472
|
+
const dst = this.object.geometry.vertices;
|
|
9473
|
+
|
|
9474
|
+
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
|
9475
|
+
|
|
9476
|
+
},
|
|
9477
|
+
|
|
9478
|
+
addNormal: function ( a, b, c ) {
|
|
9479
|
+
|
|
9480
|
+
const src = this.normals;
|
|
9481
|
+
const dst = this.object.geometry.normals;
|
|
9482
|
+
|
|
9483
|
+
dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
|
9484
|
+
dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
|
|
9485
|
+
dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
|
|
9486
|
+
|
|
9487
|
+
},
|
|
9488
|
+
|
|
9489
|
+
addFaceNormal: function ( a, b, c ) {
|
|
9490
|
+
|
|
9491
|
+
const src = this.vertices;
|
|
9492
|
+
const dst = this.object.geometry.normals;
|
|
9493
|
+
|
|
9494
|
+
_vA.fromArray( src, a );
|
|
9495
|
+
_vB.fromArray( src, b );
|
|
9496
|
+
_vC.fromArray( src, c );
|
|
9497
|
+
|
|
9498
|
+
_cb.subVectors( _vC, _vB );
|
|
9499
|
+
_ab.subVectors( _vA, _vB );
|
|
9500
|
+
_cb.cross( _ab );
|
|
9501
|
+
|
|
9502
|
+
_cb.normalize();
|
|
9503
|
+
|
|
9504
|
+
dst.push( _cb.x, _cb.y, _cb.z );
|
|
9505
|
+
dst.push( _cb.x, _cb.y, _cb.z );
|
|
9506
|
+
dst.push( _cb.x, _cb.y, _cb.z );
|
|
9507
|
+
|
|
9508
|
+
},
|
|
9509
|
+
|
|
9510
|
+
addColor: function ( a, b, c ) {
|
|
9511
|
+
|
|
9512
|
+
const src = this.colors;
|
|
9513
|
+
const dst = this.object.geometry.colors;
|
|
9514
|
+
|
|
9515
|
+
if ( src[ a ] !== undefined ) dst.push( src[ a + 0 ], src[ a + 1 ], src[ a + 2 ] );
|
|
9516
|
+
if ( src[ b ] !== undefined ) dst.push( src[ b + 0 ], src[ b + 1 ], src[ b + 2 ] );
|
|
9517
|
+
if ( src[ c ] !== undefined ) dst.push( src[ c + 0 ], src[ c + 1 ], src[ c + 2 ] );
|
|
9518
|
+
|
|
9519
|
+
},
|
|
9520
|
+
|
|
9521
|
+
addUV: function ( a, b, c ) {
|
|
9522
|
+
|
|
9523
|
+
const src = this.uvs;
|
|
9524
|
+
const dst = this.object.geometry.uvs;
|
|
9525
|
+
|
|
9526
|
+
dst.push( src[ a + 0 ], src[ a + 1 ] );
|
|
9527
|
+
dst.push( src[ b + 0 ], src[ b + 1 ] );
|
|
9528
|
+
dst.push( src[ c + 0 ], src[ c + 1 ] );
|
|
9529
|
+
|
|
9530
|
+
},
|
|
9531
|
+
|
|
9532
|
+
addDefaultUV: function () {
|
|
9533
|
+
|
|
9534
|
+
const dst = this.object.geometry.uvs;
|
|
9535
|
+
|
|
9536
|
+
dst.push( 0, 0 );
|
|
9537
|
+
dst.push( 0, 0 );
|
|
9538
|
+
dst.push( 0, 0 );
|
|
9539
|
+
|
|
9540
|
+
},
|
|
9541
|
+
|
|
9542
|
+
addUVLine: function ( a ) {
|
|
9543
|
+
|
|
9544
|
+
const src = this.uvs;
|
|
9545
|
+
const dst = this.object.geometry.uvs;
|
|
9546
|
+
|
|
9547
|
+
dst.push( src[ a + 0 ], src[ a + 1 ] );
|
|
9548
|
+
|
|
9549
|
+
},
|
|
9550
|
+
|
|
9551
|
+
addFace: function ( a, b, c, ua, ub, uc, na, nb, nc ) {
|
|
9552
|
+
|
|
9553
|
+
const vLen = this.vertices.length;
|
|
9554
|
+
|
|
9555
|
+
let ia = this.parseVertexIndex( a, vLen );
|
|
9556
|
+
let ib = this.parseVertexIndex( b, vLen );
|
|
9557
|
+
let ic = this.parseVertexIndex( c, vLen );
|
|
9558
|
+
|
|
9559
|
+
this.addVertex( ia, ib, ic );
|
|
9560
|
+
this.addColor( ia, ib, ic );
|
|
9561
|
+
|
|
9562
|
+
// normals
|
|
9563
|
+
|
|
9564
|
+
if ( na !== undefined && na !== '' ) {
|
|
9565
|
+
|
|
9566
|
+
const nLen = this.normals.length;
|
|
9567
|
+
|
|
9568
|
+
ia = this.parseNormalIndex( na, nLen );
|
|
9569
|
+
ib = this.parseNormalIndex( nb, nLen );
|
|
9570
|
+
ic = this.parseNormalIndex( nc, nLen );
|
|
9571
|
+
|
|
9572
|
+
this.addNormal( ia, ib, ic );
|
|
9573
|
+
|
|
9574
|
+
} else {
|
|
9575
|
+
|
|
9576
|
+
this.addFaceNormal( ia, ib, ic );
|
|
9577
|
+
|
|
9578
|
+
}
|
|
9579
|
+
|
|
9580
|
+
// uvs
|
|
9581
|
+
|
|
9582
|
+
if ( ua !== undefined && ua !== '' ) {
|
|
9583
|
+
|
|
9584
|
+
const uvLen = this.uvs.length;
|
|
9585
|
+
|
|
9586
|
+
ia = this.parseUVIndex( ua, uvLen );
|
|
9587
|
+
ib = this.parseUVIndex( ub, uvLen );
|
|
9588
|
+
ic = this.parseUVIndex( uc, uvLen );
|
|
9589
|
+
|
|
9590
|
+
this.addUV( ia, ib, ic );
|
|
9591
|
+
|
|
9592
|
+
this.object.geometry.hasUVIndices = true;
|
|
9593
|
+
|
|
9594
|
+
} else {
|
|
9595
|
+
|
|
9596
|
+
// add placeholder values (for inconsistent face definitions)
|
|
9597
|
+
|
|
9598
|
+
this.addDefaultUV();
|
|
9599
|
+
|
|
9600
|
+
}
|
|
9601
|
+
|
|
9602
|
+
},
|
|
9603
|
+
|
|
9604
|
+
addPointGeometry: function ( vertices ) {
|
|
9605
|
+
|
|
9606
|
+
this.object.geometry.type = 'Points';
|
|
9607
|
+
|
|
9608
|
+
const vLen = this.vertices.length;
|
|
9609
|
+
|
|
9610
|
+
for ( let vi = 0, l = vertices.length; vi < l; vi ++ ) {
|
|
9611
|
+
|
|
9612
|
+
const index = this.parseVertexIndex( vertices[ vi ], vLen );
|
|
9613
|
+
|
|
9614
|
+
this.addVertexPoint( index );
|
|
9615
|
+
this.addColor( index );
|
|
9616
|
+
|
|
9617
|
+
}
|
|
9618
|
+
|
|
9619
|
+
},
|
|
9620
|
+
|
|
9621
|
+
addLineGeometry: function ( vertices, uvs ) {
|
|
9622
|
+
|
|
9623
|
+
this.object.geometry.type = 'Line';
|
|
9624
|
+
|
|
9625
|
+
const vLen = this.vertices.length;
|
|
9626
|
+
const uvLen = this.uvs.length;
|
|
9627
|
+
|
|
9628
|
+
for ( let vi = 0, l = vertices.length; vi < l; vi ++ ) {
|
|
9629
|
+
|
|
9630
|
+
this.addVertexLine( this.parseVertexIndex( vertices[ vi ], vLen ) );
|
|
9631
|
+
|
|
9632
|
+
}
|
|
9633
|
+
|
|
9634
|
+
for ( let uvi = 0, l = uvs.length; uvi < l; uvi ++ ) {
|
|
9635
|
+
|
|
9636
|
+
this.addUVLine( this.parseUVIndex( uvs[ uvi ], uvLen ) );
|
|
9637
|
+
|
|
9638
|
+
}
|
|
9639
|
+
|
|
9640
|
+
}
|
|
9641
|
+
|
|
9642
|
+
};
|
|
9643
|
+
|
|
9644
|
+
state.startObject( '', false );
|
|
9645
|
+
|
|
9646
|
+
return state;
|
|
9647
|
+
|
|
9648
|
+
}
|
|
9649
|
+
|
|
9650
|
+
|
|
9651
|
+
/**
|
|
9652
|
+
* A loader for the OBJ format.
|
|
9653
|
+
*
|
|
9654
|
+
* The [OBJ format]{@link https://en.wikipedia.org/wiki/Wavefront_.obj_file} is a simple data-format that
|
|
9655
|
+
* represents 3D geometry in a human readable format as the position of each vertex, the UV position of
|
|
9656
|
+
* each texture coordinate vertex, vertex normals, and the faces that make each polygon defined as a list
|
|
9657
|
+
* of vertices, and texture vertices.
|
|
9658
|
+
*
|
|
9659
|
+
* ```js
|
|
9660
|
+
* const loader = new OBJLoader();
|
|
9661
|
+
* const object = await loader.loadAsync( 'models/monster.obj' );
|
|
9662
|
+
* scene.add( object );
|
|
9663
|
+
* ```
|
|
9664
|
+
*
|
|
9665
|
+
* @augments Loader
|
|
9666
|
+
* @three_import import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
|
|
9667
|
+
*/
|
|
9668
|
+
class OBJLoader extends THREE.Loader {
|
|
9669
|
+
|
|
9670
|
+
/**
|
|
9671
|
+
* Constructs a new OBJ loader.
|
|
9672
|
+
*
|
|
9673
|
+
* @param {LoadingManager} [manager] - The loading manager.
|
|
9674
|
+
*/
|
|
9675
|
+
constructor( manager ) {
|
|
9676
|
+
|
|
9677
|
+
super( manager );
|
|
9678
|
+
|
|
9679
|
+
/**
|
|
9680
|
+
* A reference to a material creator.
|
|
9681
|
+
*
|
|
9682
|
+
* @type {?MaterialCreator}
|
|
9683
|
+
* @default null
|
|
9684
|
+
*/
|
|
9685
|
+
this.materials = null;
|
|
9686
|
+
|
|
9687
|
+
}
|
|
9688
|
+
|
|
9689
|
+
/**
|
|
9690
|
+
* Starts loading from the given URL and passes the loaded OBJ asset
|
|
9691
|
+
* to the `onLoad()` callback.
|
|
9692
|
+
*
|
|
9693
|
+
* @param {string} url - The path/URL of the file to be loaded. This can also be a data URI.
|
|
9694
|
+
* @param {function(Group)} onLoad - Executed when the loading process has been finished.
|
|
9695
|
+
* @param {onProgressCallback} onProgress - Executed while the loading is in progress.
|
|
9696
|
+
* @param {onErrorCallback} onError - Executed when errors occur.
|
|
9697
|
+
*/
|
|
9698
|
+
load( url, onLoad, onProgress, onError ) {
|
|
9699
|
+
|
|
9700
|
+
const scope = this;
|
|
9701
|
+
|
|
9702
|
+
const loader = new THREE.FileLoader( this.manager );
|
|
9703
|
+
loader.setPath( this.path );
|
|
9704
|
+
loader.setRequestHeader( this.requestHeader );
|
|
9705
|
+
loader.setWithCredentials( this.withCredentials );
|
|
9706
|
+
loader.load( url, function ( text ) {
|
|
9707
|
+
|
|
9708
|
+
try {
|
|
9709
|
+
|
|
9710
|
+
onLoad( scope.parse( text ) );
|
|
9711
|
+
|
|
9712
|
+
} catch ( e ) {
|
|
9713
|
+
|
|
9714
|
+
if ( onError ) {
|
|
9715
|
+
|
|
9716
|
+
onError( e );
|
|
9717
|
+
|
|
9718
|
+
} else {
|
|
9719
|
+
|
|
9720
|
+
console.error( e );
|
|
9721
|
+
|
|
9722
|
+
}
|
|
9723
|
+
|
|
9724
|
+
scope.manager.itemError( url );
|
|
9725
|
+
|
|
9726
|
+
}
|
|
9727
|
+
|
|
9728
|
+
}, onProgress, onError );
|
|
9729
|
+
|
|
9730
|
+
}
|
|
9731
|
+
|
|
9732
|
+
/**
|
|
9733
|
+
* Sets the material creator for this OBJ. This object is loaded via {@link MTLLoader}.
|
|
9734
|
+
*
|
|
9735
|
+
* @param {MaterialCreator} materials - An object that creates the materials for this OBJ.
|
|
9736
|
+
* @return {OBJLoader} A reference to this loader.
|
|
9737
|
+
*/
|
|
9738
|
+
setMaterials( materials ) {
|
|
9739
|
+
|
|
9740
|
+
this.materials = materials;
|
|
9741
|
+
|
|
9742
|
+
return this;
|
|
9743
|
+
|
|
9744
|
+
}
|
|
9745
|
+
|
|
9746
|
+
/**
|
|
9747
|
+
* Parses the given OBJ data and returns the resulting group.
|
|
9748
|
+
*
|
|
9749
|
+
* @param {string} text - The raw OBJ data as a string.
|
|
9750
|
+
* @return {Group} The parsed OBJ.
|
|
9751
|
+
*/
|
|
9752
|
+
parse( text ) {
|
|
9753
|
+
|
|
9754
|
+
const state = new ParserState();
|
|
9755
|
+
|
|
9756
|
+
if ( text.indexOf( '\r\n' ) !== - 1 ) {
|
|
9757
|
+
|
|
9758
|
+
// This is faster than String.split with regex that splits on both
|
|
9759
|
+
text = text.replace( /\r\n/g, '\n' );
|
|
9760
|
+
|
|
9761
|
+
}
|
|
9762
|
+
|
|
9763
|
+
if ( text.indexOf( '\\\n' ) !== - 1 ) {
|
|
9764
|
+
|
|
9765
|
+
// join lines separated by a line continuation character (\)
|
|
9766
|
+
text = text.replace( /\\\n/g, '' );
|
|
9767
|
+
|
|
9768
|
+
}
|
|
9769
|
+
|
|
9770
|
+
const lines = text.split( '\n' );
|
|
9771
|
+
let result = [];
|
|
9772
|
+
|
|
9773
|
+
for ( let i = 0, l = lines.length; i < l; i ++ ) {
|
|
9774
|
+
|
|
9775
|
+
const line = lines[ i ].trimStart();
|
|
9776
|
+
|
|
9777
|
+
if ( line.length === 0 ) continue;
|
|
9778
|
+
|
|
9779
|
+
const lineFirstChar = line.charAt( 0 );
|
|
9780
|
+
|
|
9781
|
+
// @todo invoke passed in handler if any
|
|
9782
|
+
if ( lineFirstChar === '#' ) continue; // skip comments
|
|
9783
|
+
|
|
9784
|
+
if ( lineFirstChar === 'v' ) {
|
|
9785
|
+
|
|
9786
|
+
const data = line.split( _face_vertex_data_separator_pattern );
|
|
9787
|
+
|
|
9788
|
+
switch ( data[ 0 ] ) {
|
|
9789
|
+
|
|
9790
|
+
case 'v':
|
|
9791
|
+
state.vertices.push(
|
|
9792
|
+
parseFloat( data[ 1 ] ),
|
|
9793
|
+
parseFloat( data[ 2 ] ),
|
|
9794
|
+
parseFloat( data[ 3 ] )
|
|
9795
|
+
);
|
|
9796
|
+
if ( data.length >= 7 ) {
|
|
9797
|
+
|
|
9798
|
+
_color.setRGB(
|
|
9799
|
+
parseFloat( data[ 4 ] ),
|
|
9800
|
+
parseFloat( data[ 5 ] ),
|
|
9801
|
+
parseFloat( data[ 6 ] ),
|
|
9802
|
+
THREE.SRGBColorSpace
|
|
9803
|
+
);
|
|
9804
|
+
|
|
9805
|
+
state.colors.push( _color.r, _color.g, _color.b );
|
|
9806
|
+
|
|
9807
|
+
} else {
|
|
9808
|
+
|
|
9809
|
+
// if no colors are defined, add placeholders so color and vertex indices match
|
|
9810
|
+
|
|
9811
|
+
state.colors.push( undefined, undefined, undefined );
|
|
9812
|
+
|
|
9813
|
+
}
|
|
9814
|
+
|
|
9815
|
+
break;
|
|
9816
|
+
case 'vn':
|
|
9817
|
+
state.normals.push(
|
|
9818
|
+
parseFloat( data[ 1 ] ),
|
|
9819
|
+
parseFloat( data[ 2 ] ),
|
|
9820
|
+
parseFloat( data[ 3 ] )
|
|
9821
|
+
);
|
|
9822
|
+
break;
|
|
9823
|
+
case 'vt':
|
|
9824
|
+
state.uvs.push(
|
|
9825
|
+
parseFloat( data[ 1 ] ),
|
|
9826
|
+
parseFloat( data[ 2 ] )
|
|
9827
|
+
);
|
|
9828
|
+
break;
|
|
9829
|
+
|
|
9830
|
+
}
|
|
9831
|
+
|
|
9832
|
+
} else if ( lineFirstChar === 'f' ) {
|
|
9833
|
+
|
|
9834
|
+
const lineData = line.slice( 1 ).trim();
|
|
9835
|
+
const vertexData = lineData.split( _face_vertex_data_separator_pattern );
|
|
9836
|
+
const faceVertices = [];
|
|
9837
|
+
|
|
9838
|
+
// Parse the face vertex data into an easy to work with format
|
|
9839
|
+
|
|
9840
|
+
for ( let j = 0, jl = vertexData.length; j < jl; j ++ ) {
|
|
9841
|
+
|
|
9842
|
+
const vertex = vertexData[ j ];
|
|
9843
|
+
|
|
9844
|
+
if ( vertex.length > 0 ) {
|
|
9845
|
+
|
|
9846
|
+
const vertexParts = vertex.split( '/' );
|
|
9847
|
+
faceVertices.push( vertexParts );
|
|
9848
|
+
|
|
9849
|
+
}
|
|
9850
|
+
|
|
9851
|
+
}
|
|
9852
|
+
|
|
9853
|
+
// Draw an edge between the first vertex and all subsequent vertices to form an n-gon
|
|
9854
|
+
|
|
9855
|
+
const v1 = faceVertices[ 0 ];
|
|
9856
|
+
|
|
9857
|
+
for ( let j = 1, jl = faceVertices.length - 1; j < jl; j ++ ) {
|
|
9858
|
+
|
|
9859
|
+
const v2 = faceVertices[ j ];
|
|
9860
|
+
const v3 = faceVertices[ j + 1 ];
|
|
9861
|
+
|
|
9862
|
+
state.addFace(
|
|
9863
|
+
v1[ 0 ], v2[ 0 ], v3[ 0 ],
|
|
9864
|
+
v1[ 1 ], v2[ 1 ], v3[ 1 ],
|
|
9865
|
+
v1[ 2 ], v2[ 2 ], v3[ 2 ]
|
|
9866
|
+
);
|
|
9867
|
+
|
|
9868
|
+
}
|
|
9869
|
+
|
|
9870
|
+
} else if ( lineFirstChar === 'l' ) {
|
|
9871
|
+
|
|
9872
|
+
const lineParts = line.substring( 1 ).trim().split( ' ' );
|
|
9873
|
+
let lineVertices = [];
|
|
9874
|
+
const lineUVs = [];
|
|
9875
|
+
|
|
9876
|
+
if ( line.indexOf( '/' ) === - 1 ) {
|
|
9877
|
+
|
|
9878
|
+
lineVertices = lineParts;
|
|
9879
|
+
|
|
9880
|
+
} else {
|
|
9881
|
+
|
|
9882
|
+
for ( let li = 0, llen = lineParts.length; li < llen; li ++ ) {
|
|
9883
|
+
|
|
9884
|
+
const parts = lineParts[ li ].split( '/' );
|
|
9885
|
+
|
|
9886
|
+
if ( parts[ 0 ] !== '' ) lineVertices.push( parts[ 0 ] );
|
|
9887
|
+
if ( parts[ 1 ] !== '' ) lineUVs.push( parts[ 1 ] );
|
|
9888
|
+
|
|
9889
|
+
}
|
|
9890
|
+
|
|
9891
|
+
}
|
|
9892
|
+
|
|
9893
|
+
state.addLineGeometry( lineVertices, lineUVs );
|
|
9894
|
+
|
|
9895
|
+
} else if ( lineFirstChar === 'p' ) {
|
|
9896
|
+
|
|
9897
|
+
const lineData = line.slice( 1 ).trim();
|
|
9898
|
+
const pointData = lineData.split( ' ' );
|
|
9899
|
+
|
|
9900
|
+
state.addPointGeometry( pointData );
|
|
9901
|
+
|
|
9902
|
+
} else if ( ( result = _object_pattern.exec( line ) ) !== null ) {
|
|
9903
|
+
|
|
9904
|
+
// o object_name
|
|
9905
|
+
// or
|
|
9906
|
+
// g group_name
|
|
9907
|
+
|
|
9908
|
+
// WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
|
|
9909
|
+
// let name = result[ 0 ].slice( 1 ).trim();
|
|
9910
|
+
const name = ( ' ' + result[ 0 ].slice( 1 ).trim() ).slice( 1 );
|
|
9911
|
+
|
|
9912
|
+
state.startObject( name );
|
|
9913
|
+
|
|
9914
|
+
} else if ( _material_use_pattern.test( line ) ) {
|
|
9915
|
+
|
|
9916
|
+
// material
|
|
9917
|
+
|
|
9918
|
+
state.object.startMaterial( line.substring( 7 ).trim(), state.materialLibraries );
|
|
9919
|
+
|
|
9920
|
+
} else if ( _material_library_pattern.test( line ) ) {
|
|
9921
|
+
|
|
9922
|
+
// mtl file
|
|
9923
|
+
|
|
9924
|
+
state.materialLibraries.push( line.substring( 7 ).trim() );
|
|
9925
|
+
|
|
9926
|
+
} else if ( _map_use_pattern.test( line ) ) {
|
|
9927
|
+
|
|
9928
|
+
// the line is parsed but ignored since the loader assumes textures are defined MTL files
|
|
9929
|
+
// (according to https://www.okino.com/conv/imp_wave.htm, 'usemap' is the old-style Wavefront texture reference method)
|
|
9930
|
+
|
|
9931
|
+
console.warn( 'THREE.OBJLoader: Rendering identifier "usemap" not supported. Textures must be defined in MTL files.' );
|
|
9932
|
+
|
|
9933
|
+
} else if ( lineFirstChar === 's' ) {
|
|
9934
|
+
|
|
9935
|
+
result = line.split( ' ' );
|
|
9936
|
+
|
|
9937
|
+
// smooth shading
|
|
9938
|
+
|
|
9939
|
+
// @todo Handle files that have varying smooth values for a set of faces inside one geometry,
|
|
9940
|
+
// but does not define a usemtl for each face set.
|
|
9941
|
+
// This should be detected and a dummy material created (later MultiMaterial and geometry groups).
|
|
9942
|
+
// This requires some care to not create extra material on each smooth value for "normal" obj files.
|
|
9943
|
+
// where explicit usemtl defines geometry groups.
|
|
9944
|
+
// Example asset: examples/models/obj/cerberus/Cerberus.obj
|
|
9945
|
+
|
|
9946
|
+
/*
|
|
9947
|
+
* http://paulbourke.net/dataformats/obj/
|
|
9948
|
+
*
|
|
9949
|
+
* From chapter "Grouping" Syntax explanation "s group_number":
|
|
9950
|
+
* "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.
|
|
9951
|
+
* Polygonal elements use group numbers to put elements in different smoothing groups. For free-form
|
|
9952
|
+
* surfaces, smoothing groups are either turned on or off; there is no difference between values greater
|
|
9953
|
+
* than 0."
|
|
9954
|
+
*/
|
|
9955
|
+
if ( result.length > 1 ) {
|
|
9956
|
+
|
|
9957
|
+
const value = result[ 1 ].trim().toLowerCase();
|
|
9958
|
+
state.object.smooth = ( value !== '0' && value !== 'off' );
|
|
9959
|
+
|
|
9960
|
+
} else {
|
|
9961
|
+
|
|
9962
|
+
// ZBrush can produce "s" lines #11707
|
|
9963
|
+
state.object.smooth = true;
|
|
9964
|
+
|
|
9965
|
+
}
|
|
9966
|
+
|
|
9967
|
+
const material = state.object.currentMaterial();
|
|
9968
|
+
if ( material ) material.smooth = state.object.smooth;
|
|
9969
|
+
|
|
9970
|
+
} else {
|
|
9971
|
+
|
|
9972
|
+
// Handle null terminated files without exception
|
|
9973
|
+
if ( line === '\0' ) continue;
|
|
9974
|
+
|
|
9975
|
+
console.warn( 'THREE.OBJLoader: Unexpected line: "' + line + '"' );
|
|
9976
|
+
|
|
9977
|
+
}
|
|
9978
|
+
|
|
9979
|
+
}
|
|
9980
|
+
|
|
9981
|
+
state.finalize();
|
|
9982
|
+
|
|
9983
|
+
const container = new THREE.Group();
|
|
9984
|
+
container.materialLibraries = [].concat( state.materialLibraries );
|
|
9985
|
+
|
|
9986
|
+
const hasPrimitives = ! ( state.objects.length === 1 && state.objects[ 0 ].geometry.vertices.length === 0 );
|
|
9987
|
+
|
|
9988
|
+
if ( hasPrimitives === true ) {
|
|
9989
|
+
|
|
9990
|
+
for ( let i = 0, l = state.objects.length; i < l; i ++ ) {
|
|
9991
|
+
|
|
9992
|
+
const object = state.objects[ i ];
|
|
9993
|
+
const geometry = object.geometry;
|
|
9994
|
+
const materials = object.materials;
|
|
9995
|
+
const isLine = ( geometry.type === 'Line' );
|
|
9996
|
+
const isPoints = ( geometry.type === 'Points' );
|
|
9997
|
+
let hasVertexColors = false;
|
|
9998
|
+
|
|
9999
|
+
// Skip o/g line declarations that did not follow with any faces
|
|
10000
|
+
if ( geometry.vertices.length === 0 ) continue;
|
|
10001
|
+
|
|
10002
|
+
const buffergeometry = new THREE.BufferGeometry();
|
|
10003
|
+
|
|
10004
|
+
buffergeometry.setAttribute( 'position', new THREE.Float32BufferAttribute( geometry.vertices, 3 ) );
|
|
10005
|
+
|
|
10006
|
+
if ( geometry.normals.length > 0 ) {
|
|
10007
|
+
|
|
10008
|
+
buffergeometry.setAttribute( 'normal', new THREE.Float32BufferAttribute( geometry.normals, 3 ) );
|
|
10009
|
+
|
|
10010
|
+
}
|
|
10011
|
+
|
|
10012
|
+
if ( geometry.colors.length > 0 ) {
|
|
10013
|
+
|
|
10014
|
+
hasVertexColors = true;
|
|
10015
|
+
buffergeometry.setAttribute( 'color', new THREE.Float32BufferAttribute( geometry.colors, 3 ) );
|
|
10016
|
+
|
|
10017
|
+
}
|
|
10018
|
+
|
|
10019
|
+
if ( geometry.hasUVIndices === true ) {
|
|
10020
|
+
|
|
10021
|
+
buffergeometry.setAttribute( 'uv', new THREE.Float32BufferAttribute( geometry.uvs, 2 ) );
|
|
10022
|
+
|
|
10023
|
+
}
|
|
10024
|
+
|
|
10025
|
+
// Create materials
|
|
10026
|
+
|
|
10027
|
+
const createdMaterials = [];
|
|
10028
|
+
|
|
10029
|
+
for ( let mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
|
|
10030
|
+
|
|
10031
|
+
const sourceMaterial = materials[ mi ];
|
|
10032
|
+
const materialHash = sourceMaterial.name + '_' + sourceMaterial.smooth + '_' + hasVertexColors;
|
|
10033
|
+
let material = state.materials[ materialHash ];
|
|
10034
|
+
|
|
10035
|
+
if ( this.materials !== null ) {
|
|
10036
|
+
|
|
10037
|
+
material = this.materials.create( sourceMaterial.name );
|
|
10038
|
+
|
|
10039
|
+
// mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
|
|
10040
|
+
if ( isLine && material && ! ( material instanceof THREE.LineBasicMaterial ) ) {
|
|
10041
|
+
|
|
10042
|
+
const materialLine = new THREE.LineBasicMaterial();
|
|
10043
|
+
THREE.Material.prototype.copy.call( materialLine, material );
|
|
10044
|
+
materialLine.color.copy( material.color );
|
|
10045
|
+
material = materialLine;
|
|
10046
|
+
|
|
10047
|
+
} else if ( isPoints && material && ! ( material instanceof THREE.PointsMaterial ) ) {
|
|
10048
|
+
|
|
10049
|
+
const materialPoints = new THREE.PointsMaterial( { size: 10, sizeAttenuation: false } );
|
|
10050
|
+
THREE.Material.prototype.copy.call( materialPoints, material );
|
|
10051
|
+
materialPoints.color.copy( material.color );
|
|
10052
|
+
materialPoints.map = material.map;
|
|
10053
|
+
material = materialPoints;
|
|
10054
|
+
|
|
10055
|
+
}
|
|
10056
|
+
|
|
10057
|
+
}
|
|
10058
|
+
|
|
10059
|
+
if ( material === undefined ) {
|
|
10060
|
+
|
|
10061
|
+
if ( isLine ) {
|
|
10062
|
+
|
|
10063
|
+
material = new THREE.LineBasicMaterial();
|
|
10064
|
+
|
|
10065
|
+
} else if ( isPoints ) {
|
|
10066
|
+
|
|
10067
|
+
material = new THREE.PointsMaterial( { size: 1, sizeAttenuation: false } );
|
|
10068
|
+
|
|
10069
|
+
} else {
|
|
10070
|
+
|
|
10071
|
+
material = new THREE.MeshPhongMaterial();
|
|
10072
|
+
|
|
10073
|
+
}
|
|
10074
|
+
|
|
10075
|
+
material.name = sourceMaterial.name;
|
|
10076
|
+
material.flatShading = sourceMaterial.smooth ? false : true;
|
|
10077
|
+
material.vertexColors = hasVertexColors;
|
|
10078
|
+
|
|
10079
|
+
state.materials[ materialHash ] = material;
|
|
10080
|
+
|
|
10081
|
+
}
|
|
10082
|
+
|
|
10083
|
+
createdMaterials.push( material );
|
|
10084
|
+
|
|
10085
|
+
}
|
|
10086
|
+
|
|
10087
|
+
// Create mesh
|
|
10088
|
+
|
|
10089
|
+
let mesh;
|
|
10090
|
+
|
|
10091
|
+
if ( createdMaterials.length > 1 ) {
|
|
10092
|
+
|
|
10093
|
+
for ( let mi = 0, miLen = materials.length; mi < miLen; mi ++ ) {
|
|
10094
|
+
|
|
10095
|
+
const sourceMaterial = materials[ mi ];
|
|
10096
|
+
buffergeometry.addGroup( sourceMaterial.groupStart, sourceMaterial.groupCount, mi );
|
|
10097
|
+
|
|
10098
|
+
}
|
|
10099
|
+
|
|
10100
|
+
if ( isLine ) {
|
|
10101
|
+
|
|
10102
|
+
mesh = new THREE.LineSegments( buffergeometry, createdMaterials );
|
|
10103
|
+
|
|
10104
|
+
} else if ( isPoints ) {
|
|
10105
|
+
|
|
10106
|
+
mesh = new THREE.Points( buffergeometry, createdMaterials );
|
|
10107
|
+
|
|
10108
|
+
} else {
|
|
10109
|
+
|
|
10110
|
+
mesh = new THREE.Mesh( buffergeometry, createdMaterials );
|
|
10111
|
+
|
|
10112
|
+
}
|
|
10113
|
+
|
|
10114
|
+
} else {
|
|
10115
|
+
|
|
10116
|
+
if ( isLine ) {
|
|
10117
|
+
|
|
10118
|
+
mesh = new THREE.LineSegments( buffergeometry, createdMaterials[ 0 ] );
|
|
10119
|
+
|
|
10120
|
+
} else if ( isPoints ) {
|
|
10121
|
+
|
|
10122
|
+
mesh = new THREE.Points( buffergeometry, createdMaterials[ 0 ] );
|
|
10123
|
+
|
|
10124
|
+
} else {
|
|
10125
|
+
|
|
10126
|
+
mesh = new THREE.Mesh( buffergeometry, createdMaterials[ 0 ] );
|
|
10127
|
+
|
|
10128
|
+
}
|
|
10129
|
+
|
|
10130
|
+
}
|
|
10131
|
+
|
|
10132
|
+
mesh.name = object.name;
|
|
10133
|
+
|
|
10134
|
+
container.add( mesh );
|
|
10135
|
+
|
|
10136
|
+
}
|
|
10137
|
+
|
|
10138
|
+
} else {
|
|
10139
|
+
|
|
10140
|
+
// if there is only the default parser state object with no geometry data, interpret data as point cloud
|
|
10141
|
+
|
|
10142
|
+
if ( state.vertices.length > 0 ) {
|
|
10143
|
+
|
|
10144
|
+
const material = new THREE.PointsMaterial( { size: 1, sizeAttenuation: false } );
|
|
10145
|
+
|
|
10146
|
+
const buffergeometry = new THREE.BufferGeometry();
|
|
10147
|
+
|
|
10148
|
+
buffergeometry.setAttribute( 'position', new THREE.Float32BufferAttribute( state.vertices, 3 ) );
|
|
10149
|
+
|
|
10150
|
+
if ( state.colors.length > 0 && state.colors[ 0 ] !== undefined ) {
|
|
10151
|
+
|
|
10152
|
+
buffergeometry.setAttribute( 'color', new THREE.Float32BufferAttribute( state.colors, 3 ) );
|
|
10153
|
+
material.vertexColors = true;
|
|
10154
|
+
|
|
10155
|
+
}
|
|
10156
|
+
|
|
10157
|
+
const points = new THREE.Points( buffergeometry, material );
|
|
10158
|
+
container.add( points );
|
|
10159
|
+
|
|
10160
|
+
}
|
|
10161
|
+
|
|
10162
|
+
}
|
|
10163
|
+
|
|
10164
|
+
return container;
|
|
10165
|
+
|
|
10166
|
+
}
|
|
10167
|
+
|
|
10168
|
+
}
|
|
10169
|
+
|
|
9234
10170
|
var ModelPreloader = /*#__PURE__*/function () {
|
|
9235
10171
|
function ModelPreloader() {
|
|
9236
10172
|
_classCallCheck(this, ModelPreloader);
|
|
9237
|
-
this.modelCache = new Map(); // Cache for loaded
|
|
10173
|
+
this.modelCache = new Map(); // Cache for loaded models
|
|
9238
10174
|
this.loadingPromises = new Map(); // Track ongoing loads to prevent duplicates
|
|
9239
10175
|
this.gltfLoader = new GLTFLoader();
|
|
10176
|
+
this.objLoader = new OBJLoader();
|
|
9240
10177
|
this.isPreloading = false;
|
|
9241
10178
|
this.preloadingPromise = null;
|
|
9242
10179
|
this.componentDictionary = null;
|
|
9243
|
-
console.log('🚀 ModelPreloader initialized');
|
|
10180
|
+
console.log('🚀 ModelPreloader initialized with GLB and OBJ support');
|
|
9244
10181
|
}
|
|
9245
10182
|
|
|
9246
10183
|
/**
|
|
@@ -9253,7 +10190,7 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
9253
10190
|
value: (function () {
|
|
9254
10191
|
var _preloadAllModels = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(componentDictionary) {
|
|
9255
10192
|
var _this = this;
|
|
9256
|
-
var
|
|
10193
|
+
var modelsToLoad, preloadPromises;
|
|
9257
10194
|
return _regenerator().w(function (_context) {
|
|
9258
10195
|
while (1) switch (_context.n) {
|
|
9259
10196
|
case 0:
|
|
@@ -9274,21 +10211,33 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
9274
10211
|
this.componentDictionary = componentDictionary;
|
|
9275
10212
|
this.isPreloading = true;
|
|
9276
10213
|
console.log('🔄 Starting to preload all models from component dictionary...');
|
|
9277
|
-
|
|
9278
|
-
preloadPromises = []; // Extract all unique
|
|
10214
|
+
modelsToLoad = [];
|
|
10215
|
+
preloadPromises = []; // Extract all unique models with their types from the component dictionary
|
|
9279
10216
|
Object.keys(componentDictionary).forEach(function (componentType) {
|
|
9280
10217
|
var component = componentDictionary[componentType];
|
|
9281
10218
|
if (component && component.modelKey) {
|
|
9282
|
-
|
|
9283
|
-
|
|
10219
|
+
var modelInfo = {
|
|
10220
|
+
modelKey: component.modelKey,
|
|
10221
|
+
modelType: component.modelType || 'glb' // Default to GLB if not specified
|
|
10222
|
+
};
|
|
10223
|
+
|
|
10224
|
+
// Check if we already have this model in our list
|
|
10225
|
+
var existingModel = modelsToLoad.find(function (m) {
|
|
10226
|
+
return m.modelKey === modelInfo.modelKey;
|
|
10227
|
+
});
|
|
10228
|
+
if (!existingModel) {
|
|
10229
|
+
modelsToLoad.push(modelInfo);
|
|
9284
10230
|
}
|
|
9285
10231
|
}
|
|
9286
10232
|
});
|
|
9287
|
-
console.log("\uD83C\uDFAF Found ".concat(
|
|
10233
|
+
console.log("\uD83C\uDFAF Found ".concat(modelsToLoad.length, " unique models to preload:"));
|
|
10234
|
+
modelsToLoad.forEach(function (model) {
|
|
10235
|
+
console.log(" \uD83D\uDCE6 ".concat(model.modelKey, " (").concat(model.modelType.toUpperCase(), ")"));
|
|
10236
|
+
});
|
|
9288
10237
|
|
|
9289
10238
|
// Create preload promises for each model
|
|
9290
|
-
|
|
9291
|
-
preloadPromises.push(_this.preloadSingleModel(modelKey));
|
|
10239
|
+
modelsToLoad.forEach(function (modelInfo) {
|
|
10240
|
+
preloadPromises.push(_this.preloadSingleModel(modelInfo.modelKey, modelInfo.modelType));
|
|
9292
10241
|
});
|
|
9293
10242
|
|
|
9294
10243
|
// Wait for all models to load (or fail)
|
|
@@ -9311,7 +10260,7 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
9311
10260
|
return {
|
|
9312
10261
|
successful: successful,
|
|
9313
10262
|
failed: failed,
|
|
9314
|
-
total:
|
|
10263
|
+
total: modelsToLoad.length,
|
|
9315
10264
|
cache: _this.modelCache
|
|
9316
10265
|
};
|
|
9317
10266
|
});
|
|
@@ -9327,6 +10276,7 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
9327
10276
|
/**
|
|
9328
10277
|
* Preload a single model
|
|
9329
10278
|
* @param {string} modelKey - The model key (filename)
|
|
10279
|
+
* @param {string} modelType - The model type ('glb' or 'obj')
|
|
9330
10280
|
* @returns {Promise} Promise that resolves with the loaded model
|
|
9331
10281
|
*/
|
|
9332
10282
|
)
|
|
@@ -9335,10 +10285,13 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
9335
10285
|
value: (function () {
|
|
9336
10286
|
var _preloadSingleModel = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(modelKey) {
|
|
9337
10287
|
var _this2 = this;
|
|
9338
|
-
var
|
|
10288
|
+
var modelType,
|
|
10289
|
+
loadPromise,
|
|
10290
|
+
_args2 = arguments;
|
|
9339
10291
|
return _regenerator().w(function (_context2) {
|
|
9340
10292
|
while (1) switch (_context2.n) {
|
|
9341
10293
|
case 0:
|
|
10294
|
+
modelType = _args2.length > 1 && _args2[1] !== undefined ? _args2[1] : 'glb';
|
|
9342
10295
|
if (!this.modelCache.has(modelKey)) {
|
|
9343
10296
|
_context2.n = 1;
|
|
9344
10297
|
break;
|
|
@@ -9353,28 +10306,72 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
9353
10306
|
console.log("\u23F3 Model ".concat(modelKey, " already loading, waiting for completion"));
|
|
9354
10307
|
return _context2.a(2, this.loadingPromises.get(modelKey));
|
|
9355
10308
|
case 2:
|
|
9356
|
-
console.log("\uD83D\uDD04 Starting preload of model: ".concat(modelKey));
|
|
10309
|
+
console.log("\uD83D\uDD04 Starting preload of ".concat(modelType.toUpperCase(), " model: ").concat(modelKey));
|
|
9357
10310
|
loadPromise = new Promise(function (resolve, reject) {
|
|
9358
|
-
|
|
9359
|
-
|
|
9360
|
-
//
|
|
9361
|
-
_this2.
|
|
9362
|
-
|
|
9363
|
-
|
|
9364
|
-
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
|
|
9373
|
-
|
|
9374
|
-
|
|
9375
|
-
|
|
9376
|
-
|
|
9377
|
-
|
|
10311
|
+
var modelPath = "/library/models/".concat(modelKey);
|
|
10312
|
+
if (modelType === 'obj') {
|
|
10313
|
+
// Load OBJ model
|
|
10314
|
+
_this2.objLoader.load(modelPath, function (object) {
|
|
10315
|
+
console.log("\u2705 Successfully preloaded OBJ model: ".concat(modelKey));
|
|
10316
|
+
|
|
10317
|
+
// Apply default material to OBJ models (they don't come with materials)
|
|
10318
|
+
object.traverse(function (child) {
|
|
10319
|
+
if (child.isMesh) {
|
|
10320
|
+
if (!child.material) {
|
|
10321
|
+
child.material = new THREE__namespace.MeshStandardMaterial({
|
|
10322
|
+
color: 0x888888,
|
|
10323
|
+
metalness: 0.2,
|
|
10324
|
+
roughness: 0.8
|
|
10325
|
+
});
|
|
10326
|
+
}
|
|
10327
|
+
}
|
|
10328
|
+
});
|
|
10329
|
+
|
|
10330
|
+
// Cache the object for future use
|
|
10331
|
+
_this2.modelCache.set(modelKey, object);
|
|
10332
|
+
// Remove from loading promises
|
|
10333
|
+
_this2.loadingPromises.delete(modelKey);
|
|
10334
|
+
resolve(object);
|
|
10335
|
+
}, function (progress) {
|
|
10336
|
+
// Optional: track loading progress
|
|
10337
|
+
if (progress.lengthComputable) {
|
|
10338
|
+
var percentage = progress.loaded / progress.total * 100;
|
|
10339
|
+
if (percentage % 25 === 0) {
|
|
10340
|
+
// Log every 25%
|
|
10341
|
+
console.log("\uD83D\uDCCA Loading OBJ ".concat(modelKey, ": ").concat(percentage.toFixed(0), "%"));
|
|
10342
|
+
}
|
|
10343
|
+
}
|
|
10344
|
+
}, function (error) {
|
|
10345
|
+
console.error("\u274C Failed to preload OBJ model ".concat(modelKey, ":"), error);
|
|
10346
|
+
// Remove from loading promises
|
|
10347
|
+
_this2.loadingPromises.delete(modelKey);
|
|
10348
|
+
reject(error);
|
|
10349
|
+
});
|
|
10350
|
+
} else {
|
|
10351
|
+
// Load GLB model (default)
|
|
10352
|
+
_this2.gltfLoader.load(modelPath, function (gltf) {
|
|
10353
|
+
console.log("\u2705 Successfully preloaded GLB model: ".concat(modelKey));
|
|
10354
|
+
// Cache the scene for future use
|
|
10355
|
+
_this2.modelCache.set(modelKey, gltf.scene);
|
|
10356
|
+
// Remove from loading promises
|
|
10357
|
+
_this2.loadingPromises.delete(modelKey);
|
|
10358
|
+
resolve(gltf.scene);
|
|
10359
|
+
}, function (progress) {
|
|
10360
|
+
// Optional: track loading progress
|
|
10361
|
+
if (progress.lengthComputable) {
|
|
10362
|
+
var percentage = progress.loaded / progress.total * 100;
|
|
10363
|
+
if (percentage % 25 === 0) {
|
|
10364
|
+
// Log every 25%
|
|
10365
|
+
console.log("\uD83D\uDCCA Loading GLB ".concat(modelKey, ": ").concat(percentage.toFixed(0), "%"));
|
|
10366
|
+
}
|
|
10367
|
+
}
|
|
10368
|
+
}, function (error) {
|
|
10369
|
+
console.error("\u274C Failed to preload GLB model ".concat(modelKey, ":"), error);
|
|
10370
|
+
// Remove from loading promises
|
|
10371
|
+
_this2.loadingPromises.delete(modelKey);
|
|
10372
|
+
reject(error);
|
|
10373
|
+
});
|
|
10374
|
+
}
|
|
9378
10375
|
}); // Cache the loading promise
|
|
9379
10376
|
this.loadingPromises.set(modelKey, loadPromise);
|
|
9380
10377
|
return _context2.a(2, loadPromise);
|
|
@@ -9498,23 +10495,58 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
9498
10495
|
/**
|
|
9499
10496
|
* Force reload a specific model
|
|
9500
10497
|
* @param {string} modelKey - The model key to reload
|
|
10498
|
+
* @param {string} modelType - The model type ('glb' or 'obj'), will try to detect from component dictionary if not provided
|
|
9501
10499
|
* @returns {Promise} Promise that resolves with the reloaded model
|
|
9502
10500
|
*/
|
|
9503
10501
|
}, {
|
|
9504
10502
|
key: "reloadModel",
|
|
9505
10503
|
value: (function () {
|
|
9506
10504
|
var _reloadModel = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(modelKey) {
|
|
10505
|
+
var modelType,
|
|
10506
|
+
_i,
|
|
10507
|
+
_Object$keys,
|
|
10508
|
+
componentType,
|
|
10509
|
+
component,
|
|
10510
|
+
_args3 = arguments;
|
|
9507
10511
|
return _regenerator().w(function (_context3) {
|
|
9508
10512
|
while (1) switch (_context3.n) {
|
|
9509
10513
|
case 0:
|
|
10514
|
+
modelType = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : null;
|
|
9510
10515
|
console.log("\uD83D\uDD04 Force reloading model: ".concat(modelKey));
|
|
9511
10516
|
|
|
10517
|
+
// Try to determine model type from component dictionary if not provided
|
|
10518
|
+
if (!(!modelType && this.componentDictionary)) {
|
|
10519
|
+
_context3.n = 3;
|
|
10520
|
+
break;
|
|
10521
|
+
}
|
|
10522
|
+
_i = 0, _Object$keys = Object.keys(this.componentDictionary);
|
|
10523
|
+
case 1:
|
|
10524
|
+
if (!(_i < _Object$keys.length)) {
|
|
10525
|
+
_context3.n = 3;
|
|
10526
|
+
break;
|
|
10527
|
+
}
|
|
10528
|
+
componentType = _Object$keys[_i];
|
|
10529
|
+
component = this.componentDictionary[componentType];
|
|
10530
|
+
if (!(component && component.modelKey === modelKey)) {
|
|
10531
|
+
_context3.n = 2;
|
|
10532
|
+
break;
|
|
10533
|
+
}
|
|
10534
|
+
modelType = component.modelType || 'glb';
|
|
10535
|
+
return _context3.a(3, 3);
|
|
10536
|
+
case 2:
|
|
10537
|
+
_i++;
|
|
10538
|
+
_context3.n = 1;
|
|
10539
|
+
break;
|
|
10540
|
+
case 3:
|
|
10541
|
+
// Default to GLB if still not determined
|
|
10542
|
+
modelType = modelType || 'glb';
|
|
10543
|
+
|
|
9512
10544
|
// Remove from cache and loading promises
|
|
9513
10545
|
this.modelCache.delete(modelKey);
|
|
9514
10546
|
this.loadingPromises.delete(modelKey);
|
|
9515
10547
|
|
|
9516
10548
|
// Preload again
|
|
9517
|
-
return _context3.a(2, this.preloadSingleModel(modelKey));
|
|
10549
|
+
return _context3.a(2, this.preloadSingleModel(modelKey, modelType));
|
|
9518
10550
|
}
|
|
9519
10551
|
}, _callee3, this);
|
|
9520
10552
|
}));
|
|
@@ -9559,6 +10591,100 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
9559
10591
|
console.log('✅ Model preloader cache cleared');
|
|
9560
10592
|
}
|
|
9561
10593
|
|
|
10594
|
+
/**
|
|
10595
|
+
* Get model type from component dictionary
|
|
10596
|
+
* @param {string} modelKey - The model key
|
|
10597
|
+
* @returns {string} Model type ('glb' or 'obj')
|
|
10598
|
+
*/
|
|
10599
|
+
}, {
|
|
10600
|
+
key: "getModelType",
|
|
10601
|
+
value: function getModelType(modelKey) {
|
|
10602
|
+
if (!this.componentDictionary) {
|
|
10603
|
+
return 'glb'; // Default fallback
|
|
10604
|
+
}
|
|
10605
|
+
for (var _i2 = 0, _Object$keys2 = Object.keys(this.componentDictionary); _i2 < _Object$keys2.length; _i2++) {
|
|
10606
|
+
var componentType = _Object$keys2[_i2];
|
|
10607
|
+
var component = this.componentDictionary[componentType];
|
|
10608
|
+
if (component && component.modelKey === modelKey) {
|
|
10609
|
+
return component.modelType || 'glb';
|
|
10610
|
+
}
|
|
10611
|
+
}
|
|
10612
|
+
return 'glb'; // Default fallback
|
|
10613
|
+
}
|
|
10614
|
+
|
|
10615
|
+
/**
|
|
10616
|
+
* Load a component model by its library ID (for SceneOperationsManager compatibility)
|
|
10617
|
+
* @param {string} libraryId - The library ID to look up
|
|
10618
|
+
* @param {Function} callback - Callback function to receive the loaded model
|
|
10619
|
+
*/
|
|
10620
|
+
}, {
|
|
10621
|
+
key: "loadComponentById",
|
|
10622
|
+
value: function loadComponentById(libraryId, callback) {
|
|
10623
|
+
if (!this.componentDictionary || !libraryId || typeof callback !== 'function') {
|
|
10624
|
+
console.warn("\u26A0\uFE0F Invalid parameters for loadComponentById: libraryId=".concat(libraryId, ", callback=").concat(_typeof(callback)));
|
|
10625
|
+
callback(null);
|
|
10626
|
+
return;
|
|
10627
|
+
}
|
|
10628
|
+
|
|
10629
|
+
// Find the component data by library ID
|
|
10630
|
+
var componentData = this.componentDictionary[libraryId];
|
|
10631
|
+
if (!componentData || !componentData.modelKey) {
|
|
10632
|
+
console.warn("\u26A0\uFE0F No component found for library ID: ".concat(libraryId));
|
|
10633
|
+
callback(null);
|
|
10634
|
+
return;
|
|
10635
|
+
}
|
|
10636
|
+
var modelKey = componentData.modelKey;
|
|
10637
|
+
var modelType = componentData.modelType || 'glb';
|
|
10638
|
+
|
|
10639
|
+
// Check if model is already cached
|
|
10640
|
+
if (this.modelCache.has(modelKey)) {
|
|
10641
|
+
console.log("\uD83C\uDFAF Returning cached model for library ID ".concat(libraryId, ": ").concat(modelKey));
|
|
10642
|
+
var clonedModel = this.modelCache.get(modelKey).clone();
|
|
10643
|
+
|
|
10644
|
+
// Add dimensions if available
|
|
10645
|
+
if (componentData.boundingBox) {
|
|
10646
|
+
if (!clonedModel.userData) {
|
|
10647
|
+
clonedModel.userData = {};
|
|
10648
|
+
}
|
|
10649
|
+
clonedModel.userData.dimensions = {
|
|
10650
|
+
x: componentData.boundingBox.x,
|
|
10651
|
+
y: componentData.boundingBox.y,
|
|
10652
|
+
z: componentData.boundingBox.z
|
|
10653
|
+
};
|
|
10654
|
+
}
|
|
10655
|
+
callback(clonedModel);
|
|
10656
|
+
return;
|
|
10657
|
+
}
|
|
10658
|
+
|
|
10659
|
+
// Model not cached, need to load it
|
|
10660
|
+
console.log("\uD83D\uDD04 Loading model for library ID ".concat(libraryId, ": ").concat(modelKey, " (").concat(modelType.toUpperCase(), ")"));
|
|
10661
|
+
this.preloadSingleModel(modelKey, modelType).then(function (model) {
|
|
10662
|
+
if (model) {
|
|
10663
|
+
var _clonedModel = model.clone();
|
|
10664
|
+
|
|
10665
|
+
// Add dimensions if available
|
|
10666
|
+
if (componentData.boundingBox) {
|
|
10667
|
+
if (!_clonedModel.userData) {
|
|
10668
|
+
_clonedModel.userData = {};
|
|
10669
|
+
}
|
|
10670
|
+
_clonedModel.userData.dimensions = {
|
|
10671
|
+
x: componentData.boundingBox.x,
|
|
10672
|
+
y: componentData.boundingBox.y,
|
|
10673
|
+
z: componentData.boundingBox.z
|
|
10674
|
+
};
|
|
10675
|
+
}
|
|
10676
|
+
console.log("\u2705 Successfully loaded model for library ID ".concat(libraryId));
|
|
10677
|
+
callback(_clonedModel);
|
|
10678
|
+
} else {
|
|
10679
|
+
console.error("\u274C Failed to load model for library ID ".concat(libraryId));
|
|
10680
|
+
callback(null);
|
|
10681
|
+
}
|
|
10682
|
+
}).catch(function (error) {
|
|
10683
|
+
console.error("\u274C Error loading model for library ID ".concat(libraryId, ":"), error);
|
|
10684
|
+
callback(null);
|
|
10685
|
+
});
|
|
10686
|
+
}
|
|
10687
|
+
|
|
9562
10688
|
/**
|
|
9563
10689
|
* Get cache statistics
|
|
9564
10690
|
* @returns {Object} Cache statistics
|