@2112-lab/central-plant 0.1.13 → 0.1.16
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 +1731 -89
- package/dist/cjs/node_modules/three/examples/jsm/utils/BufferGeometryUtils.js +462 -0
- package/dist/cjs/src/index.js +4 -0
- package/dist/cjs/src/rendering/modelPreloader.js +348 -83
- package/dist/cjs/src/rendering/objProcessor.js +703 -0
- package/dist/cjs/src/testing/objProcessingDemo.js +254 -0
- package/dist/esm/node_modules/three/examples/jsm/utils/BufferGeometryUtils.js +461 -2
- package/dist/esm/src/index.js +2 -0
- package/dist/esm/src/rendering/modelPreloader.js +348 -83
- package/dist/esm/src/rendering/objProcessor.js +678 -0
- package/dist/esm/src/testing/objProcessingDemo.js +249 -0
- package/package.json +1 -1
package/dist/bundle/index.js
CHANGED
|
@@ -4315,6 +4315,465 @@ var SceneExportManager = /*#__PURE__*/function () {
|
|
|
4315
4315
|
}]);
|
|
4316
4316
|
}();
|
|
4317
4317
|
|
|
4318
|
+
/**
|
|
4319
|
+
* Merges a set of geometries into a single instance. All geometries must have compatible attributes.
|
|
4320
|
+
*
|
|
4321
|
+
* @param {Array<BufferGeometry>} geometries - The geometries to merge.
|
|
4322
|
+
* @param {boolean} [useGroups=false] - Whether to use groups or not.
|
|
4323
|
+
* @return {?BufferGeometry} The merged geometry. Returns `null` if the merge does not succeed.
|
|
4324
|
+
*/
|
|
4325
|
+
function mergeGeometries( geometries, useGroups = false ) {
|
|
4326
|
+
|
|
4327
|
+
const isIndexed = geometries[ 0 ].index !== null;
|
|
4328
|
+
|
|
4329
|
+
const attributesUsed = new Set( Object.keys( geometries[ 0 ].attributes ) );
|
|
4330
|
+
const morphAttributesUsed = new Set( Object.keys( geometries[ 0 ].morphAttributes ) );
|
|
4331
|
+
|
|
4332
|
+
const attributes = {};
|
|
4333
|
+
const morphAttributes = {};
|
|
4334
|
+
|
|
4335
|
+
const morphTargetsRelative = geometries[ 0 ].morphTargetsRelative;
|
|
4336
|
+
|
|
4337
|
+
const mergedGeometry = new THREE.BufferGeometry();
|
|
4338
|
+
|
|
4339
|
+
let offset = 0;
|
|
4340
|
+
|
|
4341
|
+
for ( let i = 0; i < geometries.length; ++ i ) {
|
|
4342
|
+
|
|
4343
|
+
const geometry = geometries[ i ];
|
|
4344
|
+
let attributesCount = 0;
|
|
4345
|
+
|
|
4346
|
+
// ensure that all geometries are indexed, or none
|
|
4347
|
+
|
|
4348
|
+
if ( isIndexed !== ( geometry.index !== null ) ) {
|
|
4349
|
+
|
|
4350
|
+
console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. All geometries must have compatible attributes; make sure index attribute exists among all geometries, or in none of them.' );
|
|
4351
|
+
return null;
|
|
4352
|
+
|
|
4353
|
+
}
|
|
4354
|
+
|
|
4355
|
+
// gather attributes, exit early if they're different
|
|
4356
|
+
|
|
4357
|
+
for ( const name in geometry.attributes ) {
|
|
4358
|
+
|
|
4359
|
+
if ( ! attributesUsed.has( name ) ) {
|
|
4360
|
+
|
|
4361
|
+
console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. All geometries must have compatible attributes; make sure "' + name + '" attribute exists among all geometries, or in none of them.' );
|
|
4362
|
+
return null;
|
|
4363
|
+
|
|
4364
|
+
}
|
|
4365
|
+
|
|
4366
|
+
if ( attributes[ name ] === undefined ) attributes[ name ] = [];
|
|
4367
|
+
|
|
4368
|
+
attributes[ name ].push( geometry.attributes[ name ] );
|
|
4369
|
+
|
|
4370
|
+
attributesCount ++;
|
|
4371
|
+
|
|
4372
|
+
}
|
|
4373
|
+
|
|
4374
|
+
// ensure geometries have the same number of attributes
|
|
4375
|
+
|
|
4376
|
+
if ( attributesCount !== attributesUsed.size ) {
|
|
4377
|
+
|
|
4378
|
+
console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. Make sure all geometries have the same number of attributes.' );
|
|
4379
|
+
return null;
|
|
4380
|
+
|
|
4381
|
+
}
|
|
4382
|
+
|
|
4383
|
+
// gather morph attributes, exit early if they're different
|
|
4384
|
+
|
|
4385
|
+
if ( morphTargetsRelative !== geometry.morphTargetsRelative ) {
|
|
4386
|
+
|
|
4387
|
+
console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. .morphTargetsRelative must be consistent throughout all geometries.' );
|
|
4388
|
+
return null;
|
|
4389
|
+
|
|
4390
|
+
}
|
|
4391
|
+
|
|
4392
|
+
for ( const name in geometry.morphAttributes ) {
|
|
4393
|
+
|
|
4394
|
+
if ( ! morphAttributesUsed.has( name ) ) {
|
|
4395
|
+
|
|
4396
|
+
console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. .morphAttributes must be consistent throughout all geometries.' );
|
|
4397
|
+
return null;
|
|
4398
|
+
|
|
4399
|
+
}
|
|
4400
|
+
|
|
4401
|
+
if ( morphAttributes[ name ] === undefined ) morphAttributes[ name ] = [];
|
|
4402
|
+
|
|
4403
|
+
morphAttributes[ name ].push( geometry.morphAttributes[ name ] );
|
|
4404
|
+
|
|
4405
|
+
}
|
|
4406
|
+
|
|
4407
|
+
if ( useGroups ) {
|
|
4408
|
+
|
|
4409
|
+
let count;
|
|
4410
|
+
|
|
4411
|
+
if ( isIndexed ) {
|
|
4412
|
+
|
|
4413
|
+
count = geometry.index.count;
|
|
4414
|
+
|
|
4415
|
+
} else if ( geometry.attributes.position !== undefined ) {
|
|
4416
|
+
|
|
4417
|
+
count = geometry.attributes.position.count;
|
|
4418
|
+
|
|
4419
|
+
} else {
|
|
4420
|
+
|
|
4421
|
+
console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. The geometry must have either an index or a position attribute' );
|
|
4422
|
+
return null;
|
|
4423
|
+
|
|
4424
|
+
}
|
|
4425
|
+
|
|
4426
|
+
mergedGeometry.addGroup( offset, count, i );
|
|
4427
|
+
|
|
4428
|
+
offset += count;
|
|
4429
|
+
|
|
4430
|
+
}
|
|
4431
|
+
|
|
4432
|
+
}
|
|
4433
|
+
|
|
4434
|
+
// merge indices
|
|
4435
|
+
|
|
4436
|
+
if ( isIndexed ) {
|
|
4437
|
+
|
|
4438
|
+
let indexOffset = 0;
|
|
4439
|
+
const mergedIndex = [];
|
|
4440
|
+
|
|
4441
|
+
for ( let i = 0; i < geometries.length; ++ i ) {
|
|
4442
|
+
|
|
4443
|
+
const index = geometries[ i ].index;
|
|
4444
|
+
|
|
4445
|
+
for ( let j = 0; j < index.count; ++ j ) {
|
|
4446
|
+
|
|
4447
|
+
mergedIndex.push( index.getX( j ) + indexOffset );
|
|
4448
|
+
|
|
4449
|
+
}
|
|
4450
|
+
|
|
4451
|
+
indexOffset += geometries[ i ].attributes.position.count;
|
|
4452
|
+
|
|
4453
|
+
}
|
|
4454
|
+
|
|
4455
|
+
mergedGeometry.setIndex( mergedIndex );
|
|
4456
|
+
|
|
4457
|
+
}
|
|
4458
|
+
|
|
4459
|
+
// merge attributes
|
|
4460
|
+
|
|
4461
|
+
for ( const name in attributes ) {
|
|
4462
|
+
|
|
4463
|
+
const mergedAttribute = mergeAttributes( attributes[ name ] );
|
|
4464
|
+
|
|
4465
|
+
if ( ! mergedAttribute ) {
|
|
4466
|
+
|
|
4467
|
+
console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed while trying to merge the ' + name + ' attribute.' );
|
|
4468
|
+
return null;
|
|
4469
|
+
|
|
4470
|
+
}
|
|
4471
|
+
|
|
4472
|
+
mergedGeometry.setAttribute( name, mergedAttribute );
|
|
4473
|
+
|
|
4474
|
+
}
|
|
4475
|
+
|
|
4476
|
+
// merge morph attributes
|
|
4477
|
+
|
|
4478
|
+
for ( const name in morphAttributes ) {
|
|
4479
|
+
|
|
4480
|
+
const numMorphTargets = morphAttributes[ name ][ 0 ].length;
|
|
4481
|
+
|
|
4482
|
+
if ( numMorphTargets === 0 ) break;
|
|
4483
|
+
|
|
4484
|
+
mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {};
|
|
4485
|
+
mergedGeometry.morphAttributes[ name ] = [];
|
|
4486
|
+
|
|
4487
|
+
for ( let i = 0; i < numMorphTargets; ++ i ) {
|
|
4488
|
+
|
|
4489
|
+
const morphAttributesToMerge = [];
|
|
4490
|
+
|
|
4491
|
+
for ( let j = 0; j < morphAttributes[ name ].length; ++ j ) {
|
|
4492
|
+
|
|
4493
|
+
morphAttributesToMerge.push( morphAttributes[ name ][ j ][ i ] );
|
|
4494
|
+
|
|
4495
|
+
}
|
|
4496
|
+
|
|
4497
|
+
const mergedMorphAttribute = mergeAttributes( morphAttributesToMerge );
|
|
4498
|
+
|
|
4499
|
+
if ( ! mergedMorphAttribute ) {
|
|
4500
|
+
|
|
4501
|
+
console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed while trying to merge the ' + name + ' morphAttribute.' );
|
|
4502
|
+
return null;
|
|
4503
|
+
|
|
4504
|
+
}
|
|
4505
|
+
|
|
4506
|
+
mergedGeometry.morphAttributes[ name ].push( mergedMorphAttribute );
|
|
4507
|
+
|
|
4508
|
+
}
|
|
4509
|
+
|
|
4510
|
+
}
|
|
4511
|
+
|
|
4512
|
+
return mergedGeometry;
|
|
4513
|
+
|
|
4514
|
+
}
|
|
4515
|
+
|
|
4516
|
+
/**
|
|
4517
|
+
* Merges a set of attributes into a single instance. All attributes must have compatible properties and types.
|
|
4518
|
+
* Instances of {@link InterleavedBufferAttribute} are not supported.
|
|
4519
|
+
*
|
|
4520
|
+
* @param {Array<BufferAttribute>} attributes - The attributes to merge.
|
|
4521
|
+
* @return {?BufferAttribute} The merged attribute. Returns `null` if the merge does not succeed.
|
|
4522
|
+
*/
|
|
4523
|
+
function mergeAttributes( attributes ) {
|
|
4524
|
+
|
|
4525
|
+
let TypedArray;
|
|
4526
|
+
let itemSize;
|
|
4527
|
+
let normalized;
|
|
4528
|
+
let gpuType = - 1;
|
|
4529
|
+
let arrayLength = 0;
|
|
4530
|
+
|
|
4531
|
+
for ( let i = 0; i < attributes.length; ++ i ) {
|
|
4532
|
+
|
|
4533
|
+
const attribute = attributes[ i ];
|
|
4534
|
+
|
|
4535
|
+
if ( TypedArray === undefined ) TypedArray = attribute.array.constructor;
|
|
4536
|
+
if ( TypedArray !== attribute.array.constructor ) {
|
|
4537
|
+
|
|
4538
|
+
console.error( 'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.array must be of consistent array types across matching attributes.' );
|
|
4539
|
+
return null;
|
|
4540
|
+
|
|
4541
|
+
}
|
|
4542
|
+
|
|
4543
|
+
if ( itemSize === undefined ) itemSize = attribute.itemSize;
|
|
4544
|
+
if ( itemSize !== attribute.itemSize ) {
|
|
4545
|
+
|
|
4546
|
+
console.error( 'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.itemSize must be consistent across matching attributes.' );
|
|
4547
|
+
return null;
|
|
4548
|
+
|
|
4549
|
+
}
|
|
4550
|
+
|
|
4551
|
+
if ( normalized === undefined ) normalized = attribute.normalized;
|
|
4552
|
+
if ( normalized !== attribute.normalized ) {
|
|
4553
|
+
|
|
4554
|
+
console.error( 'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.normalized must be consistent across matching attributes.' );
|
|
4555
|
+
return null;
|
|
4556
|
+
|
|
4557
|
+
}
|
|
4558
|
+
|
|
4559
|
+
if ( gpuType === - 1 ) gpuType = attribute.gpuType;
|
|
4560
|
+
if ( gpuType !== attribute.gpuType ) {
|
|
4561
|
+
|
|
4562
|
+
console.error( 'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.gpuType must be consistent across matching attributes.' );
|
|
4563
|
+
return null;
|
|
4564
|
+
|
|
4565
|
+
}
|
|
4566
|
+
|
|
4567
|
+
arrayLength += attribute.count * itemSize;
|
|
4568
|
+
|
|
4569
|
+
}
|
|
4570
|
+
|
|
4571
|
+
const array = new TypedArray( arrayLength );
|
|
4572
|
+
const result = new THREE.BufferAttribute( array, itemSize, normalized );
|
|
4573
|
+
let offset = 0;
|
|
4574
|
+
|
|
4575
|
+
for ( let i = 0; i < attributes.length; ++ i ) {
|
|
4576
|
+
|
|
4577
|
+
const attribute = attributes[ i ];
|
|
4578
|
+
if ( attribute.isInterleavedBufferAttribute ) {
|
|
4579
|
+
|
|
4580
|
+
const tupleOffset = offset / itemSize;
|
|
4581
|
+
for ( let j = 0, l = attribute.count; j < l; j ++ ) {
|
|
4582
|
+
|
|
4583
|
+
for ( let c = 0; c < itemSize; c ++ ) {
|
|
4584
|
+
|
|
4585
|
+
const value = attribute.getComponent( j, c );
|
|
4586
|
+
result.setComponent( j + tupleOffset, c, value );
|
|
4587
|
+
|
|
4588
|
+
}
|
|
4589
|
+
|
|
4590
|
+
}
|
|
4591
|
+
|
|
4592
|
+
} else {
|
|
4593
|
+
|
|
4594
|
+
array.set( attribute.array, offset );
|
|
4595
|
+
|
|
4596
|
+
}
|
|
4597
|
+
|
|
4598
|
+
offset += attribute.count * itemSize;
|
|
4599
|
+
|
|
4600
|
+
}
|
|
4601
|
+
|
|
4602
|
+
if ( gpuType !== undefined ) {
|
|
4603
|
+
|
|
4604
|
+
result.gpuType = gpuType;
|
|
4605
|
+
|
|
4606
|
+
}
|
|
4607
|
+
|
|
4608
|
+
return result;
|
|
4609
|
+
|
|
4610
|
+
}
|
|
4611
|
+
|
|
4612
|
+
/**
|
|
4613
|
+
* Returns a new geometry with vertices for which all similar vertex attributes (within tolerance) are merged.
|
|
4614
|
+
*
|
|
4615
|
+
* @param {BufferGeometry} geometry - The geometry to merge vertices for.
|
|
4616
|
+
* @param {number} [tolerance=1e-4] - The tolerance value.
|
|
4617
|
+
* @return {BufferGeometry} - The new geometry with merged vertices.
|
|
4618
|
+
*/
|
|
4619
|
+
function mergeVertices( geometry, tolerance = 1e-4 ) {
|
|
4620
|
+
|
|
4621
|
+
tolerance = Math.max( tolerance, Number.EPSILON );
|
|
4622
|
+
|
|
4623
|
+
// Generate an index buffer if the geometry doesn't have one, or optimize it
|
|
4624
|
+
// if it's already available.
|
|
4625
|
+
const hashToIndex = {};
|
|
4626
|
+
const indices = geometry.getIndex();
|
|
4627
|
+
const positions = geometry.getAttribute( 'position' );
|
|
4628
|
+
const vertexCount = indices ? indices.count : positions.count;
|
|
4629
|
+
|
|
4630
|
+
// next value for triangle indices
|
|
4631
|
+
let nextIndex = 0;
|
|
4632
|
+
|
|
4633
|
+
// attributes and new attribute arrays
|
|
4634
|
+
const attributeNames = Object.keys( geometry.attributes );
|
|
4635
|
+
const tmpAttributes = {};
|
|
4636
|
+
const tmpMorphAttributes = {};
|
|
4637
|
+
const newIndices = [];
|
|
4638
|
+
const getters = [ 'getX', 'getY', 'getZ', 'getW' ];
|
|
4639
|
+
const setters = [ 'setX', 'setY', 'setZ', 'setW' ];
|
|
4640
|
+
|
|
4641
|
+
// Initialize the arrays, allocating space conservatively. Extra
|
|
4642
|
+
// space will be trimmed in the last step.
|
|
4643
|
+
for ( let i = 0, l = attributeNames.length; i < l; i ++ ) {
|
|
4644
|
+
|
|
4645
|
+
const name = attributeNames[ i ];
|
|
4646
|
+
const attr = geometry.attributes[ name ];
|
|
4647
|
+
|
|
4648
|
+
tmpAttributes[ name ] = new attr.constructor(
|
|
4649
|
+
new attr.array.constructor( attr.count * attr.itemSize ),
|
|
4650
|
+
attr.itemSize,
|
|
4651
|
+
attr.normalized
|
|
4652
|
+
);
|
|
4653
|
+
|
|
4654
|
+
const morphAttributes = geometry.morphAttributes[ name ];
|
|
4655
|
+
if ( morphAttributes ) {
|
|
4656
|
+
|
|
4657
|
+
if ( ! tmpMorphAttributes[ name ] ) tmpMorphAttributes[ name ] = [];
|
|
4658
|
+
morphAttributes.forEach( ( morphAttr, i ) => {
|
|
4659
|
+
|
|
4660
|
+
const array = new morphAttr.array.constructor( morphAttr.count * morphAttr.itemSize );
|
|
4661
|
+
tmpMorphAttributes[ name ][ i ] = new morphAttr.constructor( array, morphAttr.itemSize, morphAttr.normalized );
|
|
4662
|
+
|
|
4663
|
+
} );
|
|
4664
|
+
|
|
4665
|
+
}
|
|
4666
|
+
|
|
4667
|
+
}
|
|
4668
|
+
|
|
4669
|
+
// convert the error tolerance to an amount of decimal places to truncate to
|
|
4670
|
+
const halfTolerance = tolerance * 0.5;
|
|
4671
|
+
const exponent = Math.log10( 1 / tolerance );
|
|
4672
|
+
const hashMultiplier = Math.pow( 10, exponent );
|
|
4673
|
+
const hashAdditive = halfTolerance * hashMultiplier;
|
|
4674
|
+
for ( let i = 0; i < vertexCount; i ++ ) {
|
|
4675
|
+
|
|
4676
|
+
const index = indices ? indices.getX( i ) : i;
|
|
4677
|
+
|
|
4678
|
+
// Generate a hash for the vertex attributes at the current index 'i'
|
|
4679
|
+
let hash = '';
|
|
4680
|
+
for ( let j = 0, l = attributeNames.length; j < l; j ++ ) {
|
|
4681
|
+
|
|
4682
|
+
const name = attributeNames[ j ];
|
|
4683
|
+
const attribute = geometry.getAttribute( name );
|
|
4684
|
+
const itemSize = attribute.itemSize;
|
|
4685
|
+
|
|
4686
|
+
for ( let k = 0; k < itemSize; k ++ ) {
|
|
4687
|
+
|
|
4688
|
+
// double tilde truncates the decimal value
|
|
4689
|
+
hash += `${ ~ ~ ( attribute[ getters[ k ] ]( index ) * hashMultiplier + hashAdditive ) },`;
|
|
4690
|
+
|
|
4691
|
+
}
|
|
4692
|
+
|
|
4693
|
+
}
|
|
4694
|
+
|
|
4695
|
+
// Add another reference to the vertex if it's already
|
|
4696
|
+
// used by another index
|
|
4697
|
+
if ( hash in hashToIndex ) {
|
|
4698
|
+
|
|
4699
|
+
newIndices.push( hashToIndex[ hash ] );
|
|
4700
|
+
|
|
4701
|
+
} else {
|
|
4702
|
+
|
|
4703
|
+
// copy data to the new index in the temporary attributes
|
|
4704
|
+
for ( let j = 0, l = attributeNames.length; j < l; j ++ ) {
|
|
4705
|
+
|
|
4706
|
+
const name = attributeNames[ j ];
|
|
4707
|
+
const attribute = geometry.getAttribute( name );
|
|
4708
|
+
const morphAttributes = geometry.morphAttributes[ name ];
|
|
4709
|
+
const itemSize = attribute.itemSize;
|
|
4710
|
+
const newArray = tmpAttributes[ name ];
|
|
4711
|
+
const newMorphArrays = tmpMorphAttributes[ name ];
|
|
4712
|
+
|
|
4713
|
+
for ( let k = 0; k < itemSize; k ++ ) {
|
|
4714
|
+
|
|
4715
|
+
const getterFunc = getters[ k ];
|
|
4716
|
+
const setterFunc = setters[ k ];
|
|
4717
|
+
newArray[ setterFunc ]( nextIndex, attribute[ getterFunc ]( index ) );
|
|
4718
|
+
|
|
4719
|
+
if ( morphAttributes ) {
|
|
4720
|
+
|
|
4721
|
+
for ( let m = 0, ml = morphAttributes.length; m < ml; m ++ ) {
|
|
4722
|
+
|
|
4723
|
+
newMorphArrays[ m ][ setterFunc ]( nextIndex, morphAttributes[ m ][ getterFunc ]( index ) );
|
|
4724
|
+
|
|
4725
|
+
}
|
|
4726
|
+
|
|
4727
|
+
}
|
|
4728
|
+
|
|
4729
|
+
}
|
|
4730
|
+
|
|
4731
|
+
}
|
|
4732
|
+
|
|
4733
|
+
hashToIndex[ hash ] = nextIndex;
|
|
4734
|
+
newIndices.push( nextIndex );
|
|
4735
|
+
nextIndex ++;
|
|
4736
|
+
|
|
4737
|
+
}
|
|
4738
|
+
|
|
4739
|
+
}
|
|
4740
|
+
|
|
4741
|
+
// generate result BufferGeometry
|
|
4742
|
+
const result = geometry.clone();
|
|
4743
|
+
for ( const name in geometry.attributes ) {
|
|
4744
|
+
|
|
4745
|
+
const tmpAttribute = tmpAttributes[ name ];
|
|
4746
|
+
|
|
4747
|
+
result.setAttribute( name, new tmpAttribute.constructor(
|
|
4748
|
+
tmpAttribute.array.slice( 0, nextIndex * tmpAttribute.itemSize ),
|
|
4749
|
+
tmpAttribute.itemSize,
|
|
4750
|
+
tmpAttribute.normalized,
|
|
4751
|
+
) );
|
|
4752
|
+
|
|
4753
|
+
if ( ! ( name in tmpMorphAttributes ) ) continue;
|
|
4754
|
+
|
|
4755
|
+
for ( let j = 0; j < tmpMorphAttributes[ name ].length; j ++ ) {
|
|
4756
|
+
|
|
4757
|
+
const tmpMorphAttribute = tmpMorphAttributes[ name ][ j ];
|
|
4758
|
+
|
|
4759
|
+
result.morphAttributes[ name ][ j ] = new tmpMorphAttribute.constructor(
|
|
4760
|
+
tmpMorphAttribute.array.slice( 0, nextIndex * tmpMorphAttribute.itemSize ),
|
|
4761
|
+
tmpMorphAttribute.itemSize,
|
|
4762
|
+
tmpMorphAttribute.normalized,
|
|
4763
|
+
);
|
|
4764
|
+
|
|
4765
|
+
}
|
|
4766
|
+
|
|
4767
|
+
}
|
|
4768
|
+
|
|
4769
|
+
// indices
|
|
4770
|
+
|
|
4771
|
+
result.setIndex( newIndices );
|
|
4772
|
+
|
|
4773
|
+
return result;
|
|
4774
|
+
|
|
4775
|
+
}
|
|
4776
|
+
|
|
4318
4777
|
/**
|
|
4319
4778
|
* Returns a new indexed geometry based on `TrianglesDrawMode` draw mode.
|
|
4320
4779
|
* This mode corresponds to the `gl.TRIANGLES` primitive in WebGL.
|
|
@@ -10167,17 +10626,692 @@ class OBJLoader extends THREE.Loader {
|
|
|
10167
10626
|
|
|
10168
10627
|
}
|
|
10169
10628
|
|
|
10170
|
-
var
|
|
10171
|
-
function
|
|
10172
|
-
_classCallCheck(this,
|
|
10173
|
-
this.
|
|
10174
|
-
this.
|
|
10175
|
-
this.
|
|
10176
|
-
this.
|
|
10177
|
-
this.
|
|
10178
|
-
this.
|
|
10629
|
+
var ObjProcessor = /*#__PURE__*/function () {
|
|
10630
|
+
function ObjProcessor() {
|
|
10631
|
+
_classCallCheck(this, ObjProcessor);
|
|
10632
|
+
this.indexedGeometryCache = new Map(); // Cache for indexed geometries
|
|
10633
|
+
this.geometrySizeCache = new Map(); // Cache for geometry sizes
|
|
10634
|
+
this.idbSupported = this.checkIndexedDBSupport();
|
|
10635
|
+
this.dbName = 'CentralPlantGeometryDB';
|
|
10636
|
+
this.dbVersion = 1;
|
|
10637
|
+
this.storeName = 'indexedGeometries';
|
|
10638
|
+
console.log('🔧 ObjProcessor initialized');
|
|
10639
|
+
console.log("\uD83D\uDCE6 IndexedDB supported: ".concat(this.idbSupported));
|
|
10640
|
+
}
|
|
10641
|
+
|
|
10642
|
+
/**
|
|
10643
|
+
* Check if IndexedDB is supported
|
|
10644
|
+
* @returns {boolean} True if IndexedDB is supported
|
|
10645
|
+
*/
|
|
10646
|
+
return _createClass(ObjProcessor, [{
|
|
10647
|
+
key: "checkIndexedDBSupport",
|
|
10648
|
+
value: function checkIndexedDBSupport() {
|
|
10649
|
+
if (typeof window === 'undefined') return false;
|
|
10650
|
+
return 'indexedDB' in window && window.indexedDB !== null;
|
|
10651
|
+
}
|
|
10652
|
+
|
|
10653
|
+
/**
|
|
10654
|
+
* Initialize IndexedDB for geometry storage
|
|
10655
|
+
* @returns {Promise<IDBDatabase>} Promise that resolves to the database
|
|
10656
|
+
*/
|
|
10657
|
+
}, {
|
|
10658
|
+
key: "initializeIDB",
|
|
10659
|
+
value: (function () {
|
|
10660
|
+
var _initializeIDB = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
10661
|
+
var _this = this;
|
|
10662
|
+
return _regenerator().w(function (_context) {
|
|
10663
|
+
while (1) switch (_context.n) {
|
|
10664
|
+
case 0:
|
|
10665
|
+
if (this.idbSupported) {
|
|
10666
|
+
_context.n = 1;
|
|
10667
|
+
break;
|
|
10668
|
+
}
|
|
10669
|
+
throw new Error('IndexedDB not supported');
|
|
10670
|
+
case 1:
|
|
10671
|
+
return _context.a(2, new Promise(function (resolve, reject) {
|
|
10672
|
+
var request = indexedDB.open(_this.dbName, _this.dbVersion);
|
|
10673
|
+
request.onerror = function () {
|
|
10674
|
+
console.error('❌ Failed to open IndexedDB');
|
|
10675
|
+
reject(request.error);
|
|
10676
|
+
};
|
|
10677
|
+
request.onsuccess = function () {
|
|
10678
|
+
console.log('✅ IndexedDB opened successfully');
|
|
10679
|
+
resolve(request.result);
|
|
10680
|
+
};
|
|
10681
|
+
request.onupgradeneeded = function (event) {
|
|
10682
|
+
console.log('🔄 Upgrading IndexedDB schema');
|
|
10683
|
+
var db = event.target.result;
|
|
10684
|
+
|
|
10685
|
+
// Create object store for indexed geometries
|
|
10686
|
+
if (!db.objectStoreNames.contains(_this.storeName)) {
|
|
10687
|
+
var store = db.createObjectStore(_this.storeName, {
|
|
10688
|
+
keyPath: 'modelKey'
|
|
10689
|
+
});
|
|
10690
|
+
store.createIndex('modelType', 'modelType', {
|
|
10691
|
+
unique: false
|
|
10692
|
+
});
|
|
10693
|
+
store.createIndex('sizeKB', 'sizeKB', {
|
|
10694
|
+
unique: false
|
|
10695
|
+
});
|
|
10696
|
+
console.log('📦 Created geometry object store');
|
|
10697
|
+
}
|
|
10698
|
+
};
|
|
10699
|
+
}));
|
|
10700
|
+
}
|
|
10701
|
+
}, _callee, this);
|
|
10702
|
+
}));
|
|
10703
|
+
function initializeIDB() {
|
|
10704
|
+
return _initializeIDB.apply(this, arguments);
|
|
10705
|
+
}
|
|
10706
|
+
return initializeIDB;
|
|
10707
|
+
}()
|
|
10708
|
+
/**
|
|
10709
|
+
* Convert OBJ object to indexed BufferGeometry
|
|
10710
|
+
* @param {THREE.Object3D} objObject - The loaded OBJ object from THREE.OBJLoader
|
|
10711
|
+
* @param {string} modelKey - The model key for identification
|
|
10712
|
+
* @returns {Object} Object containing indexed geometry and metadata
|
|
10713
|
+
*/
|
|
10714
|
+
)
|
|
10715
|
+
}, {
|
|
10716
|
+
key: "objToIndexedBufferGeometry",
|
|
10717
|
+
value: function objToIndexedBufferGeometry(objObject, modelKey) {
|
|
10718
|
+
var _this2 = this;
|
|
10719
|
+
console.log("\uD83D\uDD04 Converting OBJ to indexed BufferGeometry: ".concat(modelKey));
|
|
10720
|
+
var geometries = [];
|
|
10721
|
+
var materials = [];
|
|
10722
|
+
|
|
10723
|
+
// Traverse the OBJ object and collect all geometries
|
|
10724
|
+
objObject.traverse(function (child) {
|
|
10725
|
+
if (child.isMesh && child.geometry) {
|
|
10726
|
+
// Clone the geometry to avoid modifying the original
|
|
10727
|
+
var geometry = child.geometry.clone();
|
|
10728
|
+
|
|
10729
|
+
// Ensure the geometry has proper attributes
|
|
10730
|
+
if (!geometry.attributes.position) {
|
|
10731
|
+
console.warn("\u26A0\uFE0F Geometry missing position attribute: ".concat(modelKey));
|
|
10732
|
+
return;
|
|
10733
|
+
}
|
|
10734
|
+
|
|
10735
|
+
// Compute normals if missing
|
|
10736
|
+
if (!geometry.attributes.normal) {
|
|
10737
|
+
geometry.computeVertexNormals();
|
|
10738
|
+
console.log("\uD83D\uDCD0 Computed normals for geometry: ".concat(modelKey));
|
|
10739
|
+
}
|
|
10740
|
+
|
|
10741
|
+
// Compute UVs if missing (simple planar mapping)
|
|
10742
|
+
if (!geometry.attributes.uv) {
|
|
10743
|
+
_this2.computeSimpleUVs(geometry);
|
|
10744
|
+
console.log("\uD83D\uDDFA\uFE0F Computed UVs for geometry: ".concat(modelKey));
|
|
10745
|
+
}
|
|
10746
|
+
geometries.push(geometry);
|
|
10747
|
+
materials.push(child.material);
|
|
10748
|
+
}
|
|
10749
|
+
});
|
|
10750
|
+
if (geometries.length === 0) {
|
|
10751
|
+
console.warn("\u26A0\uFE0F No valid geometries found in OBJ: ".concat(modelKey));
|
|
10752
|
+
return null;
|
|
10753
|
+
}
|
|
10754
|
+
|
|
10755
|
+
// Merge all geometries into one
|
|
10756
|
+
var mergedGeometry;
|
|
10757
|
+
if (geometries.length === 1) {
|
|
10758
|
+
mergedGeometry = geometries[0];
|
|
10759
|
+
} else {
|
|
10760
|
+
console.log("\uD83D\uDD17 Merging ".concat(geometries.length, " geometries for: ").concat(modelKey));
|
|
10761
|
+
mergedGeometry = mergeGeometries(geometries);
|
|
10762
|
+
}
|
|
10763
|
+
|
|
10764
|
+
// Convert to indexed geometry if not already indexed
|
|
10765
|
+
var indexedGeometry = mergedGeometry;
|
|
10766
|
+
var originalGeometry = mergedGeometry; // Keep reference to original for comparison
|
|
10767
|
+
|
|
10768
|
+
if (!mergedGeometry.index) {
|
|
10769
|
+
console.log("\uD83D\uDCCA Converting to indexed geometry: ".concat(modelKey));
|
|
10770
|
+
indexedGeometry = mergeVertices(mergedGeometry);
|
|
10771
|
+
}
|
|
10772
|
+
|
|
10773
|
+
// Calculate geometry statistics with original geometry for comparison
|
|
10774
|
+
var stats = this.calculateGeometryStats(indexedGeometry, modelKey, originalGeometry);
|
|
10775
|
+
|
|
10776
|
+
// Prepare serializable data for storage
|
|
10777
|
+
var geometryData = this.serializeGeometry(indexedGeometry, modelKey, stats);
|
|
10778
|
+
console.log("\u2705 Successfully converted OBJ to indexed BufferGeometry: ".concat(modelKey));
|
|
10779
|
+
console.log("\uD83D\uDCCA Vertices: ".concat(stats.vertexCount, ", Faces: ").concat(stats.faceCount));
|
|
10780
|
+
console.log("\uD83D\uDCBE Indexed Size: ".concat(stats.indexedSizeKB, "KB"));
|
|
10781
|
+
if (stats.nonIndexedSizeKB > 0) {
|
|
10782
|
+
console.log("\uD83D\uDCBE Non-Indexed Size: ".concat(stats.nonIndexedSizeKB, "KB"));
|
|
10783
|
+
console.log("\uD83D\uDD04 Memory Reduction: ".concat(stats.memoryReduction, "% (").concat(stats.compressionRatio, "x smaller)"));
|
|
10784
|
+
}
|
|
10785
|
+
return {
|
|
10786
|
+
geometry: indexedGeometry,
|
|
10787
|
+
geometryData: geometryData,
|
|
10788
|
+
stats: stats,
|
|
10789
|
+
materials: materials[0] || new THREE__namespace.MeshStandardMaterial({
|
|
10790
|
+
color: 0x888888
|
|
10791
|
+
})
|
|
10792
|
+
};
|
|
10793
|
+
}
|
|
10794
|
+
|
|
10795
|
+
/**
|
|
10796
|
+
* Compute simple planar UVs for geometry
|
|
10797
|
+
* @param {THREE.BufferGeometry} geometry - The geometry to compute UVs for
|
|
10798
|
+
*/
|
|
10799
|
+
}, {
|
|
10800
|
+
key: "computeSimpleUVs",
|
|
10801
|
+
value: function computeSimpleUVs(geometry) {
|
|
10802
|
+
var positions = geometry.attributes.position;
|
|
10803
|
+
var uvs = new Float32Array(positions.count * 2);
|
|
10804
|
+
|
|
10805
|
+
// Simple planar projection on XZ plane
|
|
10806
|
+
for (var i = 0; i < positions.count; i++) {
|
|
10807
|
+
var x = positions.getX(i);
|
|
10808
|
+
var z = positions.getZ(i);
|
|
10809
|
+
|
|
10810
|
+
// Normalize to 0-1 range (simple box projection)
|
|
10811
|
+
uvs[i * 2] = (x + 1) * 0.5;
|
|
10812
|
+
uvs[i * 2 + 1] = (z + 1) * 0.5;
|
|
10813
|
+
}
|
|
10814
|
+
geometry.setAttribute('uv', new THREE__namespace.BufferAttribute(uvs, 2));
|
|
10815
|
+
}
|
|
10816
|
+
|
|
10817
|
+
/**
|
|
10818
|
+
* Calculate geometry statistics
|
|
10819
|
+
* @param {THREE.BufferGeometry} geometry - The geometry to analyze
|
|
10820
|
+
* @param {string} modelKey - The model key for logging
|
|
10821
|
+
* @param {THREE.BufferGeometry} originalGeometry - Optional original non-indexed geometry for comparison
|
|
10822
|
+
* @returns {Object} Statistics object
|
|
10823
|
+
*/
|
|
10824
|
+
}, {
|
|
10825
|
+
key: "calculateGeometryStats",
|
|
10826
|
+
value: function calculateGeometryStats(geometry, modelKey) {
|
|
10827
|
+
var originalGeometry = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
10828
|
+
var vertexCount = geometry.attributes.position.count;
|
|
10829
|
+
var faceCount = geometry.index ? geometry.index.count / 3 : vertexCount / 3;
|
|
10830
|
+
|
|
10831
|
+
// Calculate indexed geometry memory usage
|
|
10832
|
+
var indexedBytes = 0;
|
|
10833
|
+
|
|
10834
|
+
// Position attribute (3 floats per vertex)
|
|
10835
|
+
if (geometry.attributes.position) {
|
|
10836
|
+
indexedBytes += geometry.attributes.position.array.byteLength;
|
|
10837
|
+
}
|
|
10838
|
+
|
|
10839
|
+
// Normal attribute (3 floats per vertex)
|
|
10840
|
+
if (geometry.attributes.normal) {
|
|
10841
|
+
indexedBytes += geometry.attributes.normal.array.byteLength;
|
|
10842
|
+
}
|
|
10843
|
+
|
|
10844
|
+
// UV attribute (2 floats per vertex)
|
|
10845
|
+
if (geometry.attributes.uv) {
|
|
10846
|
+
indexedBytes += geometry.attributes.uv.array.byteLength;
|
|
10847
|
+
}
|
|
10848
|
+
|
|
10849
|
+
// Index buffer (if indexed)
|
|
10850
|
+
if (geometry.index) {
|
|
10851
|
+
indexedBytes += geometry.index.array.byteLength;
|
|
10852
|
+
}
|
|
10853
|
+
var indexedSizeKB = (indexedBytes / 1024).toFixed(2);
|
|
10854
|
+
|
|
10855
|
+
// Calculate non-indexed geometry memory usage for comparison
|
|
10856
|
+
var nonIndexedBytes = 0;
|
|
10857
|
+
var nonIndexedSizeKB = 0;
|
|
10858
|
+
var memoryReduction = 0;
|
|
10859
|
+
var compressionRatio = 1;
|
|
10860
|
+
if (originalGeometry) {
|
|
10861
|
+
// Calculate what the memory would be without indexing
|
|
10862
|
+
var originalVertexCount = originalGeometry.attributes.position ? originalGeometry.attributes.position.count : vertexCount;
|
|
10863
|
+
|
|
10864
|
+
// Position: 3 floats per vertex
|
|
10865
|
+
nonIndexedBytes += originalVertexCount * 3 * 4; // 4 bytes per float32
|
|
10866
|
+
|
|
10867
|
+
// Normals: 3 floats per vertex (if present)
|
|
10868
|
+
if (originalGeometry.attributes.normal || geometry.attributes.normal) {
|
|
10869
|
+
nonIndexedBytes += originalVertexCount * 3 * 4;
|
|
10870
|
+
}
|
|
10871
|
+
|
|
10872
|
+
// UVs: 2 floats per vertex (if present)
|
|
10873
|
+
if (originalGeometry.attributes.uv || geometry.attributes.uv) {
|
|
10874
|
+
nonIndexedBytes += originalVertexCount * 2 * 4;
|
|
10875
|
+
}
|
|
10876
|
+
nonIndexedSizeKB = (nonIndexedBytes / 1024).toFixed(2);
|
|
10877
|
+
memoryReduction = ((nonIndexedBytes - indexedBytes) / nonIndexedBytes * 100).toFixed(1);
|
|
10878
|
+
compressionRatio = (nonIndexedBytes / indexedBytes).toFixed(2);
|
|
10879
|
+
} else if (geometry.index) {
|
|
10880
|
+
// Estimate non-indexed size based on face count
|
|
10881
|
+
var estimatedNonIndexedVertices = faceCount * 3; // Each face has 3 vertices
|
|
10882
|
+
|
|
10883
|
+
// Position: 3 floats per vertex
|
|
10884
|
+
nonIndexedBytes += estimatedNonIndexedVertices * 3 * 4;
|
|
10885
|
+
|
|
10886
|
+
// Normals: 3 floats per vertex (if present)
|
|
10887
|
+
if (geometry.attributes.normal) {
|
|
10888
|
+
nonIndexedBytes += estimatedNonIndexedVertices * 3 * 4;
|
|
10889
|
+
}
|
|
10890
|
+
|
|
10891
|
+
// UVs: 2 floats per vertex (if present)
|
|
10892
|
+
if (geometry.attributes.uv) {
|
|
10893
|
+
nonIndexedBytes += estimatedNonIndexedVertices * 2 * 4;
|
|
10894
|
+
}
|
|
10895
|
+
nonIndexedSizeKB = (nonIndexedBytes / 1024).toFixed(2);
|
|
10896
|
+
memoryReduction = ((nonIndexedBytes - indexedBytes) / nonIndexedBytes * 100).toFixed(1);
|
|
10897
|
+
compressionRatio = (nonIndexedBytes / indexedBytes).toFixed(2);
|
|
10898
|
+
}
|
|
10899
|
+
var stats = {
|
|
10900
|
+
modelKey: modelKey,
|
|
10901
|
+
vertexCount: vertexCount,
|
|
10902
|
+
faceCount: faceCount,
|
|
10903
|
+
// Indexed geometry stats
|
|
10904
|
+
indexedBytes: indexedBytes,
|
|
10905
|
+
indexedSizeKB: parseFloat(indexedSizeKB),
|
|
10906
|
+
// Non-indexed geometry stats (for comparison)
|
|
10907
|
+
nonIndexedBytes: nonIndexedBytes,
|
|
10908
|
+
nonIndexedSizeKB: parseFloat(nonIndexedSizeKB),
|
|
10909
|
+
// Compression metrics
|
|
10910
|
+
memoryReduction: parseFloat(memoryReduction),
|
|
10911
|
+
// Percentage reduction
|
|
10912
|
+
compressionRatio: parseFloat(compressionRatio),
|
|
10913
|
+
// How many times smaller
|
|
10914
|
+
// Legacy compatibility
|
|
10915
|
+
totalBytes: indexedBytes,
|
|
10916
|
+
// Keep for backward compatibility
|
|
10917
|
+
sizeKB: parseFloat(indexedSizeKB),
|
|
10918
|
+
// Keep for backward compatibility
|
|
10919
|
+
// Features
|
|
10920
|
+
indexed: !!geometry.index,
|
|
10921
|
+
hasNormals: !!geometry.attributes.normal,
|
|
10922
|
+
hasUVs: !!geometry.attributes.uv,
|
|
10923
|
+
timestamp: Date.now()
|
|
10924
|
+
};
|
|
10925
|
+
|
|
10926
|
+
// Cache the size info
|
|
10927
|
+
this.geometrySizeCache.set(modelKey, stats);
|
|
10928
|
+
return stats;
|
|
10929
|
+
}
|
|
10930
|
+
|
|
10931
|
+
/**
|
|
10932
|
+
* Serialize geometry for storage
|
|
10933
|
+
* @param {THREE.BufferGeometry} geometry - The geometry to serialize
|
|
10934
|
+
* @param {string} modelKey - The model key
|
|
10935
|
+
* @param {Object} stats - The geometry statistics
|
|
10936
|
+
* @returns {Object} Serializable geometry data
|
|
10937
|
+
*/
|
|
10938
|
+
}, {
|
|
10939
|
+
key: "serializeGeometry",
|
|
10940
|
+
value: function serializeGeometry(geometry, modelKey, stats) {
|
|
10941
|
+
var data = {
|
|
10942
|
+
modelKey: modelKey,
|
|
10943
|
+
modelType: 'obj',
|
|
10944
|
+
stats: stats,
|
|
10945
|
+
attributes: {}
|
|
10946
|
+
};
|
|
10947
|
+
|
|
10948
|
+
// Serialize position attribute
|
|
10949
|
+
if (geometry.attributes.position) {
|
|
10950
|
+
data.attributes.position = {
|
|
10951
|
+
array: Array.from(geometry.attributes.position.array),
|
|
10952
|
+
itemSize: geometry.attributes.position.itemSize,
|
|
10953
|
+
normalized: geometry.attributes.position.normalized
|
|
10954
|
+
};
|
|
10955
|
+
}
|
|
10956
|
+
|
|
10957
|
+
// Serialize normal attribute
|
|
10958
|
+
if (geometry.attributes.normal) {
|
|
10959
|
+
data.attributes.normal = {
|
|
10960
|
+
array: Array.from(geometry.attributes.normal.array),
|
|
10961
|
+
itemSize: geometry.attributes.normal.itemSize,
|
|
10962
|
+
normalized: geometry.attributes.normal.normalized
|
|
10963
|
+
};
|
|
10964
|
+
}
|
|
10965
|
+
|
|
10966
|
+
// Serialize UV attribute
|
|
10967
|
+
if (geometry.attributes.uv) {
|
|
10968
|
+
data.attributes.uv = {
|
|
10969
|
+
array: Array.from(geometry.attributes.uv.array),
|
|
10970
|
+
itemSize: geometry.attributes.uv.itemSize,
|
|
10971
|
+
normalized: geometry.attributes.uv.normalized
|
|
10972
|
+
};
|
|
10973
|
+
}
|
|
10974
|
+
|
|
10975
|
+
// Serialize index
|
|
10976
|
+
if (geometry.index) {
|
|
10977
|
+
data.index = {
|
|
10978
|
+
array: Array.from(geometry.index.array),
|
|
10979
|
+
itemSize: 1
|
|
10980
|
+
};
|
|
10981
|
+
}
|
|
10982
|
+
return data;
|
|
10983
|
+
}
|
|
10984
|
+
|
|
10985
|
+
/**
|
|
10986
|
+
* Deserialize geometry data back to BufferGeometry
|
|
10987
|
+
* @param {Object} geometryData - The serialized geometry data
|
|
10988
|
+
* @returns {THREE.BufferGeometry} The reconstructed geometry
|
|
10989
|
+
*/
|
|
10990
|
+
}, {
|
|
10991
|
+
key: "deserializeGeometry",
|
|
10992
|
+
value: function deserializeGeometry(geometryData) {
|
|
10993
|
+
var geometry = new THREE__namespace.BufferGeometry();
|
|
10994
|
+
|
|
10995
|
+
// Restore attributes
|
|
10996
|
+
Object.keys(geometryData.attributes).forEach(function (attributeName) {
|
|
10997
|
+
var attrData = geometryData.attributes[attributeName];
|
|
10998
|
+
var array = new Float32Array(attrData.array);
|
|
10999
|
+
var attribute = new THREE__namespace.BufferAttribute(array, attrData.itemSize, attrData.normalized);
|
|
11000
|
+
geometry.setAttribute(attributeName, attribute);
|
|
11001
|
+
});
|
|
11002
|
+
|
|
11003
|
+
// Restore index if present
|
|
11004
|
+
if (geometryData.index) {
|
|
11005
|
+
var indexArray = new Uint32Array(geometryData.index.array);
|
|
11006
|
+
geometry.setIndex(new THREE__namespace.BufferAttribute(indexArray, 1));
|
|
11007
|
+
}
|
|
11008
|
+
return geometry;
|
|
11009
|
+
}
|
|
11010
|
+
|
|
11011
|
+
/**
|
|
11012
|
+
* Store indexed geometry in IndexedDB
|
|
11013
|
+
* @param {Object} geometryData - The serialized geometry data
|
|
11014
|
+
* @returns {Promise} Promise that resolves when stored
|
|
11015
|
+
*/
|
|
11016
|
+
}, {
|
|
11017
|
+
key: "storeGeometryInIDB",
|
|
11018
|
+
value: (function () {
|
|
11019
|
+
var _storeGeometryInIDB = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(geometryData) {
|
|
11020
|
+
var _this3 = this;
|
|
11021
|
+
var db, _t;
|
|
11022
|
+
return _regenerator().w(function (_context2) {
|
|
11023
|
+
while (1) switch (_context2.n) {
|
|
11024
|
+
case 0:
|
|
11025
|
+
if (this.idbSupported) {
|
|
11026
|
+
_context2.n = 1;
|
|
11027
|
+
break;
|
|
11028
|
+
}
|
|
11029
|
+
console.warn('⚠️ IndexedDB not supported, skipping storage');
|
|
11030
|
+
return _context2.a(2);
|
|
11031
|
+
case 1:
|
|
11032
|
+
_context2.p = 1;
|
|
11033
|
+
_context2.n = 2;
|
|
11034
|
+
return this.initializeIDB();
|
|
11035
|
+
case 2:
|
|
11036
|
+
db = _context2.v;
|
|
11037
|
+
return _context2.a(2, new Promise(function (resolve, reject) {
|
|
11038
|
+
var transaction = db.transaction([_this3.storeName], 'readwrite');
|
|
11039
|
+
var store = transaction.objectStore(_this3.storeName);
|
|
11040
|
+
var request = store.put(geometryData);
|
|
11041
|
+
request.onsuccess = function () {
|
|
11042
|
+
console.log("\uD83D\uDCBE Stored geometry in IndexedDB: ".concat(geometryData.modelKey));
|
|
11043
|
+
resolve();
|
|
11044
|
+
};
|
|
11045
|
+
request.onerror = function () {
|
|
11046
|
+
console.error("\u274C Failed to store geometry: ".concat(geometryData.modelKey));
|
|
11047
|
+
reject(request.error);
|
|
11048
|
+
};
|
|
11049
|
+
}));
|
|
11050
|
+
case 3:
|
|
11051
|
+
_context2.p = 3;
|
|
11052
|
+
_t = _context2.v;
|
|
11053
|
+
console.error('❌ Error storing geometry in IndexedDB:', _t);
|
|
11054
|
+
throw _t;
|
|
11055
|
+
case 4:
|
|
11056
|
+
return _context2.a(2);
|
|
11057
|
+
}
|
|
11058
|
+
}, _callee2, this, [[1, 3]]);
|
|
11059
|
+
}));
|
|
11060
|
+
function storeGeometryInIDB(_x) {
|
|
11061
|
+
return _storeGeometryInIDB.apply(this, arguments);
|
|
11062
|
+
}
|
|
11063
|
+
return storeGeometryInIDB;
|
|
11064
|
+
}()
|
|
11065
|
+
/**
|
|
11066
|
+
* Load indexed geometry from IndexedDB
|
|
11067
|
+
* @param {string} modelKey - The model key to load
|
|
11068
|
+
* @returns {Promise<Object>} Promise that resolves to geometry data
|
|
11069
|
+
*/
|
|
11070
|
+
)
|
|
11071
|
+
}, {
|
|
11072
|
+
key: "loadGeometryFromIDB",
|
|
11073
|
+
value: (function () {
|
|
11074
|
+
var _loadGeometryFromIDB = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(modelKey) {
|
|
11075
|
+
var _this4 = this;
|
|
11076
|
+
var db, _t2;
|
|
11077
|
+
return _regenerator().w(function (_context3) {
|
|
11078
|
+
while (1) switch (_context3.n) {
|
|
11079
|
+
case 0:
|
|
11080
|
+
if (this.idbSupported) {
|
|
11081
|
+
_context3.n = 1;
|
|
11082
|
+
break;
|
|
11083
|
+
}
|
|
11084
|
+
console.warn('⚠️ IndexedDB not supported, cannot load');
|
|
11085
|
+
return _context3.a(2, null);
|
|
11086
|
+
case 1:
|
|
11087
|
+
_context3.p = 1;
|
|
11088
|
+
_context3.n = 2;
|
|
11089
|
+
return this.initializeIDB();
|
|
11090
|
+
case 2:
|
|
11091
|
+
db = _context3.v;
|
|
11092
|
+
return _context3.a(2, new Promise(function (resolve, reject) {
|
|
11093
|
+
var transaction = db.transaction([_this4.storeName], 'readonly');
|
|
11094
|
+
var store = transaction.objectStore(_this4.storeName);
|
|
11095
|
+
var request = store.get(modelKey);
|
|
11096
|
+
request.onsuccess = function () {
|
|
11097
|
+
if (request.result) {
|
|
11098
|
+
console.log("\uD83D\uDCE6 Loaded geometry from IndexedDB: ".concat(modelKey));
|
|
11099
|
+
resolve(request.result);
|
|
11100
|
+
} else {
|
|
11101
|
+
console.log("\uD83D\uDCED No geometry found in IndexedDB: ".concat(modelKey));
|
|
11102
|
+
resolve(null);
|
|
11103
|
+
}
|
|
11104
|
+
};
|
|
11105
|
+
request.onerror = function () {
|
|
11106
|
+
console.error("\u274C Failed to load geometry: ".concat(modelKey));
|
|
11107
|
+
reject(request.error);
|
|
11108
|
+
};
|
|
11109
|
+
}));
|
|
11110
|
+
case 3:
|
|
11111
|
+
_context3.p = 3;
|
|
11112
|
+
_t2 = _context3.v;
|
|
11113
|
+
console.error('❌ Error loading geometry from IndexedDB:', _t2);
|
|
11114
|
+
throw _t2;
|
|
11115
|
+
case 4:
|
|
11116
|
+
return _context3.a(2);
|
|
11117
|
+
}
|
|
11118
|
+
}, _callee3, this, [[1, 3]]);
|
|
11119
|
+
}));
|
|
11120
|
+
function loadGeometryFromIDB(_x2) {
|
|
11121
|
+
return _loadGeometryFromIDB.apply(this, arguments);
|
|
11122
|
+
}
|
|
11123
|
+
return loadGeometryFromIDB;
|
|
11124
|
+
}()
|
|
11125
|
+
/**
|
|
11126
|
+
* Create a custom mesh from indexed geometry
|
|
11127
|
+
* @param {string} modelKey - The model key
|
|
11128
|
+
* @param {THREE.Material} material - Optional material to use
|
|
11129
|
+
* @returns {THREE.Mesh|null} The created mesh or null if not found
|
|
11130
|
+
*/
|
|
11131
|
+
)
|
|
11132
|
+
}, {
|
|
11133
|
+
key: "createCustomMesh",
|
|
11134
|
+
value: function createCustomMesh(modelKey) {
|
|
11135
|
+
var material = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
11136
|
+
if (this.indexedGeometryCache.has(modelKey)) {
|
|
11137
|
+
var cachedData = this.indexedGeometryCache.get(modelKey);
|
|
11138
|
+
var geometry = cachedData.geometry.clone();
|
|
11139
|
+
var defaultMaterial = new THREE__namespace.MeshStandardMaterial({
|
|
11140
|
+
color: 0x888888,
|
|
11141
|
+
side: THREE__namespace.DoubleSide,
|
|
11142
|
+
wireframe: false
|
|
11143
|
+
});
|
|
11144
|
+
var mesh = new THREE__namespace.Mesh(geometry, material || defaultMaterial);
|
|
11145
|
+
mesh.userData.modelKey = modelKey;
|
|
11146
|
+
mesh.userData.stats = cachedData.stats;
|
|
11147
|
+
mesh.userData.isCustomGeometry = true;
|
|
11148
|
+
console.log("\uD83C\uDFAF Created custom mesh from indexed geometry: ".concat(modelKey));
|
|
11149
|
+
return mesh;
|
|
11150
|
+
}
|
|
11151
|
+
console.warn("\u26A0\uFE0F Indexed geometry not found in cache: ".concat(modelKey));
|
|
11152
|
+
return null;
|
|
11153
|
+
}
|
|
11154
|
+
|
|
11155
|
+
/**
|
|
11156
|
+
* Process an OBJ object and store the result
|
|
11157
|
+
* @param {THREE.Object3D} objObject - The loaded OBJ object
|
|
11158
|
+
* @param {string} modelKey - The model key
|
|
11159
|
+
* @param {boolean} storeInIDB - Whether to store in IndexedDB
|
|
11160
|
+
* @returns {Promise<Object>} Promise that resolves to the processed result
|
|
11161
|
+
*/
|
|
11162
|
+
}, {
|
|
11163
|
+
key: "processObjObject",
|
|
11164
|
+
value: (function () {
|
|
11165
|
+
var _processObjObject = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(objObject, modelKey) {
|
|
11166
|
+
var storeInIDB,
|
|
11167
|
+
result,
|
|
11168
|
+
_args4 = arguments,
|
|
11169
|
+
_t3;
|
|
11170
|
+
return _regenerator().w(function (_context4) {
|
|
11171
|
+
while (1) switch (_context4.n) {
|
|
11172
|
+
case 0:
|
|
11173
|
+
storeInIDB = _args4.length > 2 && _args4[2] !== undefined ? _args4[2] : true;
|
|
11174
|
+
_context4.p = 1;
|
|
11175
|
+
// Convert to indexed BufferGeometry
|
|
11176
|
+
result = this.objToIndexedBufferGeometry(objObject, modelKey);
|
|
11177
|
+
if (result) {
|
|
11178
|
+
_context4.n = 2;
|
|
11179
|
+
break;
|
|
11180
|
+
}
|
|
11181
|
+
throw new Error("Failed to convert OBJ to indexed geometry: ".concat(modelKey));
|
|
11182
|
+
case 2:
|
|
11183
|
+
// Cache the result
|
|
11184
|
+
this.indexedGeometryCache.set(modelKey, result);
|
|
11185
|
+
|
|
11186
|
+
// Store in IndexedDB if requested
|
|
11187
|
+
if (!(storeInIDB && result.geometryData)) {
|
|
11188
|
+
_context4.n = 3;
|
|
11189
|
+
break;
|
|
11190
|
+
}
|
|
11191
|
+
_context4.n = 3;
|
|
11192
|
+
return this.storeGeometryInIDB(result.geometryData);
|
|
11193
|
+
case 3:
|
|
11194
|
+
console.log("\u2705 Successfully processed OBJ: ".concat(modelKey));
|
|
11195
|
+
return _context4.a(2, result);
|
|
11196
|
+
case 4:
|
|
11197
|
+
_context4.p = 4;
|
|
11198
|
+
_t3 = _context4.v;
|
|
11199
|
+
console.error("\u274C Error processing OBJ: ".concat(modelKey), _t3);
|
|
11200
|
+
throw _t3;
|
|
11201
|
+
case 5:
|
|
11202
|
+
return _context4.a(2);
|
|
11203
|
+
}
|
|
11204
|
+
}, _callee4, this, [[1, 4]]);
|
|
11205
|
+
}));
|
|
11206
|
+
function processObjObject(_x3, _x4) {
|
|
11207
|
+
return _processObjObject.apply(this, arguments);
|
|
11208
|
+
}
|
|
11209
|
+
return processObjObject;
|
|
11210
|
+
}()
|
|
11211
|
+
/**
|
|
11212
|
+
* Get all processed geometry statistics
|
|
11213
|
+
* @returns {Array} Array of geometry statistics
|
|
11214
|
+
*/
|
|
11215
|
+
)
|
|
11216
|
+
}, {
|
|
11217
|
+
key: "getAllGeometryStats",
|
|
11218
|
+
value: function getAllGeometryStats() {
|
|
11219
|
+
var stats = [];
|
|
11220
|
+
this.geometrySizeCache.forEach(function (stat, modelKey) {
|
|
11221
|
+
stats.push(stat);
|
|
11222
|
+
});
|
|
11223
|
+
return stats.sort(function (a, b) {
|
|
11224
|
+
return b.sizeKB - a.sizeKB;
|
|
11225
|
+
}); // Sort by size descending
|
|
11226
|
+
}
|
|
11227
|
+
|
|
11228
|
+
/**
|
|
11229
|
+
* Get total memory usage of cached geometries
|
|
11230
|
+
* @returns {Object} Memory usage statistics
|
|
11231
|
+
*/
|
|
11232
|
+
}, {
|
|
11233
|
+
key: "getMemoryUsage",
|
|
11234
|
+
value: function getMemoryUsage() {
|
|
11235
|
+
var totalIndexedBytes = 0;
|
|
11236
|
+
var totalNonIndexedBytes = 0;
|
|
11237
|
+
var totalGeometries = 0;
|
|
11238
|
+
this.geometrySizeCache.forEach(function (stats) {
|
|
11239
|
+
totalIndexedBytes += stats.indexedBytes;
|
|
11240
|
+
totalNonIndexedBytes += stats.nonIndexedBytes;
|
|
11241
|
+
totalGeometries++;
|
|
11242
|
+
});
|
|
11243
|
+
var totalMemoryReduction = totalNonIndexedBytes > 0 ? ((totalNonIndexedBytes - totalIndexedBytes) / totalNonIndexedBytes * 100).toFixed(1) : 0;
|
|
11244
|
+
var totalCompressionRatio = totalIndexedBytes > 0 ? (totalNonIndexedBytes / totalIndexedBytes).toFixed(2) : 1;
|
|
11245
|
+
return {
|
|
11246
|
+
totalGeometries: totalGeometries,
|
|
11247
|
+
// Indexed geometry stats
|
|
11248
|
+
indexedBytes: totalIndexedBytes,
|
|
11249
|
+
indexedKB: (totalIndexedBytes / 1024).toFixed(2),
|
|
11250
|
+
indexedMB: (totalIndexedBytes / (1024 * 1024)).toFixed(3),
|
|
11251
|
+
// Non-indexed geometry stats
|
|
11252
|
+
nonIndexedBytes: totalNonIndexedBytes,
|
|
11253
|
+
nonIndexedKB: (totalNonIndexedBytes / 1024).toFixed(2),
|
|
11254
|
+
nonIndexedMB: (totalNonIndexedBytes / (1024 * 1024)).toFixed(3),
|
|
11255
|
+
// Compression stats
|
|
11256
|
+
memoryReduction: parseFloat(totalMemoryReduction),
|
|
11257
|
+
compressionRatio: parseFloat(totalCompressionRatio),
|
|
11258
|
+
// Legacy compatibility
|
|
11259
|
+
totalBytes: totalIndexedBytes,
|
|
11260
|
+
totalKB: (totalIndexedBytes / 1024).toFixed(2),
|
|
11261
|
+
totalMB: (totalIndexedBytes / (1024 * 1024)).toFixed(2)
|
|
11262
|
+
};
|
|
11263
|
+
}
|
|
11264
|
+
|
|
11265
|
+
/**
|
|
11266
|
+
* Clear all caches
|
|
11267
|
+
*/
|
|
11268
|
+
}, {
|
|
11269
|
+
key: "clearCaches",
|
|
11270
|
+
value: function clearCaches() {
|
|
11271
|
+
console.log('🧹 Clearing OBJ processor caches...');
|
|
11272
|
+
|
|
11273
|
+
// Dispose of cached geometries
|
|
11274
|
+
this.indexedGeometryCache.forEach(function (data, modelKey) {
|
|
11275
|
+
if (data.geometry) {
|
|
11276
|
+
data.geometry.dispose();
|
|
11277
|
+
}
|
|
11278
|
+
console.log("\uD83D\uDDD1\uFE0F Disposed cached geometry: ".concat(modelKey));
|
|
11279
|
+
});
|
|
11280
|
+
this.indexedGeometryCache.clear();
|
|
11281
|
+
this.geometrySizeCache.clear();
|
|
11282
|
+
console.log('✅ OBJ processor caches cleared');
|
|
11283
|
+
}
|
|
11284
|
+
|
|
11285
|
+
/**
|
|
11286
|
+
* Get processing status
|
|
11287
|
+
* @returns {Object} Status information
|
|
11288
|
+
*/
|
|
11289
|
+
}, {
|
|
11290
|
+
key: "getStatus",
|
|
11291
|
+
value: function getStatus() {
|
|
11292
|
+
return {
|
|
11293
|
+
cachedGeometries: Array.from(this.indexedGeometryCache.keys()),
|
|
11294
|
+
totalCached: this.indexedGeometryCache.size,
|
|
11295
|
+
idbSupported: this.idbSupported,
|
|
11296
|
+
memoryUsage: this.getMemoryUsage()
|
|
11297
|
+
};
|
|
11298
|
+
}
|
|
11299
|
+
}]);
|
|
11300
|
+
}(); // Export the class
|
|
11301
|
+
|
|
11302
|
+
var ModelPreloader = /*#__PURE__*/function () {
|
|
11303
|
+
function ModelPreloader() {
|
|
11304
|
+
_classCallCheck(this, ModelPreloader);
|
|
11305
|
+
this.modelCache = new Map(); // Cache for loaded models
|
|
11306
|
+
this.loadingPromises = new Map(); // Track ongoing loads to prevent duplicates
|
|
11307
|
+
this.gltfLoader = new GLTFLoader();
|
|
11308
|
+
this.objLoader = new OBJLoader();
|
|
11309
|
+
this.objProcessor = new ObjProcessor(); // Initialize OBJ processor
|
|
11310
|
+
this.isPreloading = false;
|
|
11311
|
+
this.preloadingPromise = null;
|
|
10179
11312
|
this.componentDictionary = null;
|
|
10180
11313
|
console.log('🚀 ModelPreloader initialized with GLB and OBJ support');
|
|
11314
|
+
console.log('🔧 OBJ Processor integrated for indexed BufferGeometry conversion');
|
|
10181
11315
|
}
|
|
10182
11316
|
|
|
10183
11317
|
/**
|
|
@@ -10283,93 +11417,137 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
10283
11417
|
}, {
|
|
10284
11418
|
key: "preloadSingleModel",
|
|
10285
11419
|
value: (function () {
|
|
10286
|
-
var _preloadSingleModel = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
11420
|
+
var _preloadSingleModel = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(modelKey) {
|
|
10287
11421
|
var _this2 = this;
|
|
10288
11422
|
var modelType,
|
|
10289
11423
|
loadPromise,
|
|
10290
|
-
|
|
10291
|
-
return _regenerator().w(function (
|
|
10292
|
-
while (1) switch (
|
|
11424
|
+
_args3 = arguments;
|
|
11425
|
+
return _regenerator().w(function (_context3) {
|
|
11426
|
+
while (1) switch (_context3.n) {
|
|
10293
11427
|
case 0:
|
|
10294
|
-
modelType =
|
|
11428
|
+
modelType = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : 'glb';
|
|
10295
11429
|
if (!this.modelCache.has(modelKey)) {
|
|
10296
|
-
|
|
11430
|
+
_context3.n = 1;
|
|
10297
11431
|
break;
|
|
10298
11432
|
}
|
|
10299
11433
|
console.log("\uD83C\uDFAF Model ".concat(modelKey, " already cached, skipping"));
|
|
10300
|
-
return
|
|
11434
|
+
return _context3.a(2, this.modelCache.get(modelKey));
|
|
10301
11435
|
case 1:
|
|
10302
11436
|
if (!this.loadingPromises.has(modelKey)) {
|
|
10303
|
-
|
|
11437
|
+
_context3.n = 2;
|
|
10304
11438
|
break;
|
|
10305
11439
|
}
|
|
10306
11440
|
console.log("\u23F3 Model ".concat(modelKey, " already loading, waiting for completion"));
|
|
10307
|
-
return
|
|
11441
|
+
return _context3.a(2, this.loadingPromises.get(modelKey));
|
|
10308
11442
|
case 2:
|
|
10309
11443
|
console.log("\uD83D\uDD04 Starting preload of ".concat(modelType.toUpperCase(), " model: ").concat(modelKey));
|
|
10310
11444
|
loadPromise = new Promise(function (resolve, reject) {
|
|
10311
11445
|
var modelPath = "/library/models/".concat(modelKey);
|
|
10312
|
-
if (modelType === 'obj') {
|
|
10313
|
-
// Load OBJ model
|
|
10314
|
-
_this2.objLoader.load(modelPath, function (
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
|
|
10325
|
-
|
|
10326
|
-
|
|
10327
|
-
|
|
10328
|
-
|
|
11446
|
+
if (modelType === 'obj') {
|
|
11447
|
+
// Load OBJ model with advanced processing
|
|
11448
|
+
_this2.objLoader.load(modelPath, /*#__PURE__*/function () {
|
|
11449
|
+
var _ref = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(object) {
|
|
11450
|
+
var processedResult, modelData, _t;
|
|
11451
|
+
return _regenerator().w(function (_context2) {
|
|
11452
|
+
while (1) switch (_context2.n) {
|
|
11453
|
+
case 0:
|
|
11454
|
+
_context2.p = 0;
|
|
11455
|
+
console.log("\u2705 Successfully loaded OBJ model: ".concat(modelKey));
|
|
11456
|
+
|
|
11457
|
+
// Process OBJ with the new processor for indexed BufferGeometry
|
|
11458
|
+
_context2.n = 1;
|
|
11459
|
+
return _this2.objProcessor.processObjObject(object, modelKey, true);
|
|
11460
|
+
case 1:
|
|
11461
|
+
processedResult = _context2.v;
|
|
11462
|
+
if (!processedResult) {
|
|
11463
|
+
_context2.n = 2;
|
|
11464
|
+
break;
|
|
11465
|
+
}
|
|
11466
|
+
console.log("\uD83D\uDD27 OBJ processed to indexed BufferGeometry: ".concat(modelKey));
|
|
11467
|
+
console.log("\uD83D\uDCCA Geometry stats:", processedResult.stats);
|
|
11468
|
+
|
|
11469
|
+
// Apply double-sided materials with solid + wireframe overlay
|
|
11470
|
+
object.traverse(function (child) {
|
|
11471
|
+
if (child.isMesh) {
|
|
11472
|
+
// Create solid material
|
|
11473
|
+
var solidMaterial = new THREE__namespace.MeshStandardMaterial({
|
|
11474
|
+
color: child.material.color || 0x888888,
|
|
11475
|
+
side: THREE__namespace.DoubleSide,
|
|
11476
|
+
wireframe: false
|
|
11477
|
+
// transparent: true,
|
|
11478
|
+
// opacity: 0.8 // Slightly transparent to show wireframe better
|
|
11479
|
+
});
|
|
10329
11480
|
|
|
10330
|
-
|
|
10331
|
-
|
|
10332
|
-
|
|
10333
|
-
|
|
10334
|
-
|
|
10335
|
-
|
|
10336
|
-
|
|
10337
|
-
|
|
11481
|
+
// Create wireframe material
|
|
11482
|
+
var wireframeMaterial = new THREE__namespace.MeshBasicMaterial({
|
|
11483
|
+
color: 0x000000,
|
|
11484
|
+
// Black wireframe
|
|
11485
|
+
wireframe: true,
|
|
11486
|
+
// transparent: true,
|
|
11487
|
+
// opacity: 0.6,
|
|
11488
|
+
side: THREE__namespace.DoubleSide
|
|
11489
|
+
});
|
|
10338
11490
|
|
|
10339
|
-
|
|
10340
|
-
|
|
10341
|
-
wireframeMesh.name = child.name + '_wireframe';
|
|
11491
|
+
// Apply solid material to the original mesh
|
|
11492
|
+
child.material = solidMaterial;
|
|
10342
11493
|
|
|
10343
|
-
|
|
10344
|
-
|
|
10345
|
-
|
|
10346
|
-
|
|
10347
|
-
|
|
11494
|
+
// Create a wireframe mesh clone and add it as a child
|
|
11495
|
+
var wireframeMesh = new THREE__namespace.Mesh(child.geometry, wireframeMaterial);
|
|
11496
|
+
wireframeMesh.position.copy(child.position);
|
|
11497
|
+
wireframeMesh.rotation.copy(child.rotation);
|
|
11498
|
+
wireframeMesh.scale.copy(child.scale);
|
|
11499
|
+
wireframeMesh.name = child.name + '_wireframe';
|
|
11500
|
+
wireframeMesh.userData.isWireframeOverlay = true;
|
|
10348
11501
|
|
|
10349
|
-
|
|
10350
|
-
|
|
10351
|
-
|
|
11502
|
+
// Add wireframe mesh to the same parent
|
|
11503
|
+
if (child.parent) {
|
|
11504
|
+
child.parent.add(wireframeMesh);
|
|
11505
|
+
}
|
|
11506
|
+
}
|
|
11507
|
+
});
|
|
11508
|
+
// Store both the original object and processed data
|
|
11509
|
+
modelData = {
|
|
11510
|
+
originalObject: object,
|
|
11511
|
+
processedGeometry: processedResult.geometry,
|
|
11512
|
+
geometryStats: processedResult.stats,
|
|
11513
|
+
materials: processedResult.materials,
|
|
11514
|
+
isObjModel: true
|
|
11515
|
+
}; // Cache the model data
|
|
11516
|
+
_this2.modelCache.set(modelKey, modelData);
|
|
11517
|
+
_this2.loadingPromises.delete(modelKey);
|
|
11518
|
+
resolve(modelData);
|
|
11519
|
+
_context2.n = 3;
|
|
11520
|
+
break;
|
|
11521
|
+
case 2:
|
|
11522
|
+
throw new Error('Failed to process OBJ to indexed geometry');
|
|
11523
|
+
case 3:
|
|
11524
|
+
_context2.n = 5;
|
|
11525
|
+
break;
|
|
11526
|
+
case 4:
|
|
11527
|
+
_context2.p = 4;
|
|
11528
|
+
_t = _context2.v;
|
|
11529
|
+
console.error("\u274C Error processing OBJ model ".concat(modelKey, ":"), _t);
|
|
11530
|
+
// Fallback: cache the original object without processing
|
|
11531
|
+
_this2.modelCache.set(modelKey, object);
|
|
11532
|
+
_this2.loadingPromises.delete(modelKey);
|
|
11533
|
+
resolve(object);
|
|
11534
|
+
case 5:
|
|
11535
|
+
return _context2.a(2);
|
|
10352
11536
|
}
|
|
10353
|
-
}
|
|
10354
|
-
});
|
|
10355
|
-
|
|
10356
|
-
|
|
10357
|
-
|
|
10358
|
-
|
|
10359
|
-
_this2.loadingPromises.delete(modelKey);
|
|
10360
|
-
resolve(object);
|
|
10361
|
-
}, function (progress) {
|
|
10362
|
-
// Optional: track loading progress
|
|
11537
|
+
}, _callee2, null, [[0, 4]]);
|
|
11538
|
+
}));
|
|
11539
|
+
return function (_x3) {
|
|
11540
|
+
return _ref.apply(this, arguments);
|
|
11541
|
+
};
|
|
11542
|
+
}(), function (progress) {
|
|
10363
11543
|
if (progress.lengthComputable) {
|
|
10364
11544
|
var percentage = progress.loaded / progress.total * 100;
|
|
10365
11545
|
if (percentage % 25 === 0) {
|
|
10366
|
-
// Log every 25%
|
|
10367
11546
|
console.log("\uD83D\uDCCA Loading OBJ ".concat(modelKey, ": ").concat(percentage.toFixed(0), "%"));
|
|
10368
11547
|
}
|
|
10369
11548
|
}
|
|
10370
11549
|
}, function (error) {
|
|
10371
11550
|
console.error("\u274C Failed to preload OBJ model ".concat(modelKey, ":"), error);
|
|
10372
|
-
// Remove from loading promises
|
|
10373
11551
|
_this2.loadingPromises.delete(modelKey);
|
|
10374
11552
|
reject(error);
|
|
10375
11553
|
});
|
|
@@ -10400,9 +11578,9 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
10400
11578
|
}
|
|
10401
11579
|
}); // Cache the loading promise
|
|
10402
11580
|
this.loadingPromises.set(modelKey, loadPromise);
|
|
10403
|
-
return
|
|
11581
|
+
return _context3.a(2, loadPromise);
|
|
10404
11582
|
}
|
|
10405
|
-
},
|
|
11583
|
+
}, _callee3, this);
|
|
10406
11584
|
}));
|
|
10407
11585
|
function preloadSingleModel(_x2) {
|
|
10408
11586
|
return _preloadSingleModel.apply(this, arguments);
|
|
@@ -10412,18 +11590,42 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
10412
11590
|
/**
|
|
10413
11591
|
* Get a cached model (cloned for use)
|
|
10414
11592
|
* @param {string} modelKey - The model key
|
|
11593
|
+
* @param {boolean} useIndexedGeometry - Whether to use indexed geometry for OBJ models
|
|
10415
11594
|
* @returns {THREE.Object3D|null} Cloned model or null if not found
|
|
10416
11595
|
*/
|
|
10417
11596
|
)
|
|
10418
11597
|
}, {
|
|
10419
11598
|
key: "getCachedModel",
|
|
10420
11599
|
value: function getCachedModel(modelKey) {
|
|
11600
|
+
var useIndexedGeometry = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
10421
11601
|
if (this.modelCache.has(modelKey)) {
|
|
10422
11602
|
console.log("\uD83C\uDFAF Returning cached model: ".concat(modelKey));
|
|
10423
|
-
var
|
|
11603
|
+
var cachedData = this.modelCache.get(modelKey);
|
|
11604
|
+
|
|
11605
|
+
// Handle OBJ models with processed geometry
|
|
11606
|
+
if (cachedData && cachedData.isObjModel && useIndexedGeometry && cachedData.processedGeometry) {
|
|
11607
|
+
console.log("\uD83D\uDD27 Using indexed BufferGeometry for OBJ: ".concat(modelKey));
|
|
11608
|
+
|
|
11609
|
+
// Create a mesh from the processed indexed geometry
|
|
11610
|
+
var mesh = new THREE__namespace.Mesh(cachedData.processedGeometry.clone(), cachedData.materials.clone());
|
|
10424
11611
|
|
|
10425
|
-
|
|
10426
|
-
|
|
11612
|
+
// Add metadata
|
|
11613
|
+
mesh.userData.modelKey = modelKey;
|
|
11614
|
+
mesh.userData.geometryStats = cachedData.geometryStats;
|
|
11615
|
+
mesh.userData.isIndexedGeometry = true;
|
|
11616
|
+
mesh.userData.originalSizeKB = cachedData.geometryStats.sizeKB;
|
|
11617
|
+
return mesh;
|
|
11618
|
+
}
|
|
11619
|
+
|
|
11620
|
+
// Handle regular models or OBJ models without indexed geometry
|
|
11621
|
+
var modelToClone = cachedData.isObjModel ? cachedData.originalObject : cachedData;
|
|
11622
|
+
var clonedModel = modelToClone.clone();
|
|
11623
|
+
|
|
11624
|
+
// Add OBJ stats if available
|
|
11625
|
+
if (cachedData.isObjModel && cachedData.geometryStats) {
|
|
11626
|
+
clonedModel.userData.geometryStats = cachedData.geometryStats;
|
|
11627
|
+
clonedModel.userData.isObjModel = true;
|
|
11628
|
+
}
|
|
10427
11629
|
return clonedModel;
|
|
10428
11630
|
}
|
|
10429
11631
|
console.warn("\u26A0\uFE0F Model ".concat(modelKey, " not found in cache"));
|
|
@@ -10442,7 +11644,26 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
10442
11644
|
var libraryId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
10443
11645
|
if (this.modelCache.has(modelKey)) {
|
|
10444
11646
|
console.log("\uD83C\uDFAF Returning cached model with dimensions: ".concat(modelKey));
|
|
10445
|
-
var
|
|
11647
|
+
var cachedData = this.modelCache.get(modelKey);
|
|
11648
|
+
|
|
11649
|
+
// Handle OBJ models with processed geometry structure
|
|
11650
|
+
var clonedModel;
|
|
11651
|
+
if (cachedData && cachedData.isObjModel) {
|
|
11652
|
+
// Clone the original OBJ object
|
|
11653
|
+
clonedModel = cachedData.originalObject.clone();
|
|
11654
|
+
|
|
11655
|
+
// Add OBJ stats if available
|
|
11656
|
+
if (cachedData.geometryStats) {
|
|
11657
|
+
if (!clonedModel.userData) {
|
|
11658
|
+
clonedModel.userData = {};
|
|
11659
|
+
}
|
|
11660
|
+
clonedModel.userData.geometryStats = cachedData.geometryStats;
|
|
11661
|
+
clonedModel.userData.isObjModel = true;
|
|
11662
|
+
}
|
|
11663
|
+
} else {
|
|
11664
|
+
// Handle regular GLB models
|
|
11665
|
+
clonedModel = cachedData.clone();
|
|
11666
|
+
}
|
|
10446
11667
|
|
|
10447
11668
|
// Add dimensions from component dictionary if available
|
|
10448
11669
|
if (libraryId && this.componentDictionary) {
|
|
@@ -10531,41 +11752,41 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
10531
11752
|
}, {
|
|
10532
11753
|
key: "reloadModel",
|
|
10533
11754
|
value: (function () {
|
|
10534
|
-
var _reloadModel = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function
|
|
11755
|
+
var _reloadModel = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(modelKey) {
|
|
10535
11756
|
var modelType,
|
|
10536
11757
|
_i,
|
|
10537
11758
|
_Object$keys,
|
|
10538
11759
|
componentType,
|
|
10539
11760
|
component,
|
|
10540
|
-
|
|
10541
|
-
return _regenerator().w(function (
|
|
10542
|
-
while (1) switch (
|
|
11761
|
+
_args4 = arguments;
|
|
11762
|
+
return _regenerator().w(function (_context4) {
|
|
11763
|
+
while (1) switch (_context4.n) {
|
|
10543
11764
|
case 0:
|
|
10544
|
-
modelType =
|
|
11765
|
+
modelType = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : null;
|
|
10545
11766
|
console.log("\uD83D\uDD04 Force reloading model: ".concat(modelKey));
|
|
10546
11767
|
|
|
10547
11768
|
// Try to determine model type from component dictionary if not provided
|
|
10548
11769
|
if (!(!modelType && this.componentDictionary)) {
|
|
10549
|
-
|
|
11770
|
+
_context4.n = 3;
|
|
10550
11771
|
break;
|
|
10551
11772
|
}
|
|
10552
11773
|
_i = 0, _Object$keys = Object.keys(this.componentDictionary);
|
|
10553
11774
|
case 1:
|
|
10554
11775
|
if (!(_i < _Object$keys.length)) {
|
|
10555
|
-
|
|
11776
|
+
_context4.n = 3;
|
|
10556
11777
|
break;
|
|
10557
11778
|
}
|
|
10558
11779
|
componentType = _Object$keys[_i];
|
|
10559
11780
|
component = this.componentDictionary[componentType];
|
|
10560
11781
|
if (!(component && component.modelKey === modelKey)) {
|
|
10561
|
-
|
|
11782
|
+
_context4.n = 2;
|
|
10562
11783
|
break;
|
|
10563
11784
|
}
|
|
10564
11785
|
modelType = component.modelType || 'glb';
|
|
10565
|
-
return
|
|
11786
|
+
return _context4.a(3, 3);
|
|
10566
11787
|
case 2:
|
|
10567
11788
|
_i++;
|
|
10568
|
-
|
|
11789
|
+
_context4.n = 1;
|
|
10569
11790
|
break;
|
|
10570
11791
|
case 3:
|
|
10571
11792
|
// Default to GLB if still not determined
|
|
@@ -10576,11 +11797,11 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
10576
11797
|
this.loadingPromises.delete(modelKey);
|
|
10577
11798
|
|
|
10578
11799
|
// Preload again
|
|
10579
|
-
return
|
|
11800
|
+
return _context4.a(2, this.preloadSingleModel(modelKey, modelType));
|
|
10580
11801
|
}
|
|
10581
|
-
},
|
|
11802
|
+
}, _callee4, this);
|
|
10582
11803
|
}));
|
|
10583
|
-
function reloadModel(
|
|
11804
|
+
function reloadModel(_x4) {
|
|
10584
11805
|
return _reloadModel.apply(this, arguments);
|
|
10585
11806
|
}
|
|
10586
11807
|
return reloadModel;
|
|
@@ -10597,7 +11818,42 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
10597
11818
|
// Dispose of all cached models
|
|
10598
11819
|
this.modelCache.forEach(function (model, modelKey) {
|
|
10599
11820
|
console.log("\uD83D\uDDD1\uFE0F Disposing cached model: ".concat(modelKey));
|
|
10600
|
-
if (model && model.
|
|
11821
|
+
if (model && model.isObjModel) {
|
|
11822
|
+
// Handle OBJ model data structure
|
|
11823
|
+
if (model.originalObject && model.originalObject.traverse) {
|
|
11824
|
+
model.originalObject.traverse(function (child) {
|
|
11825
|
+
if (child.geometry) {
|
|
11826
|
+
child.geometry.dispose();
|
|
11827
|
+
}
|
|
11828
|
+
if (child.material) {
|
|
11829
|
+
if (Array.isArray(child.material)) {
|
|
11830
|
+
child.material.forEach(function (material) {
|
|
11831
|
+
return material.dispose();
|
|
11832
|
+
});
|
|
11833
|
+
} else {
|
|
11834
|
+
child.material.dispose();
|
|
11835
|
+
}
|
|
11836
|
+
}
|
|
11837
|
+
});
|
|
11838
|
+
}
|
|
11839
|
+
|
|
11840
|
+
// Dispose processed geometry
|
|
11841
|
+
if (model.processedGeometry) {
|
|
11842
|
+
model.processedGeometry.dispose();
|
|
11843
|
+
}
|
|
11844
|
+
|
|
11845
|
+
// Dispose materials
|
|
11846
|
+
if (model.materials) {
|
|
11847
|
+
if (Array.isArray(model.materials)) {
|
|
11848
|
+
model.materials.forEach(function (material) {
|
|
11849
|
+
return material.dispose();
|
|
11850
|
+
});
|
|
11851
|
+
} else {
|
|
11852
|
+
model.materials.dispose();
|
|
11853
|
+
}
|
|
11854
|
+
}
|
|
11855
|
+
} else if (model && model.traverse) {
|
|
11856
|
+
// Handle regular model
|
|
10601
11857
|
model.traverse(function (child) {
|
|
10602
11858
|
if (child.geometry) {
|
|
10603
11859
|
child.geometry.dispose();
|
|
@@ -10618,6 +11874,9 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
10618
11874
|
this.loadingPromises.clear();
|
|
10619
11875
|
this.isPreloading = false;
|
|
10620
11876
|
this.preloadingPromise = null;
|
|
11877
|
+
|
|
11878
|
+
// Clear OBJ processor caches
|
|
11879
|
+
this.objProcessor.clearCaches();
|
|
10621
11880
|
console.log('✅ Model preloader cache cleared');
|
|
10622
11881
|
}
|
|
10623
11882
|
|
|
@@ -10690,7 +11949,24 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
10690
11949
|
console.log("\uD83D\uDD04 Loading model for library ID ".concat(libraryId, ": ").concat(modelKey, " (").concat(modelType.toUpperCase(), ")"));
|
|
10691
11950
|
this.preloadSingleModel(modelKey, modelType).then(function (model) {
|
|
10692
11951
|
if (model) {
|
|
10693
|
-
|
|
11952
|
+
// Handle OBJ models with processed geometry structure
|
|
11953
|
+
var _clonedModel;
|
|
11954
|
+
if (model && model.isObjModel) {
|
|
11955
|
+
// Clone the original OBJ object
|
|
11956
|
+
_clonedModel = model.originalObject.clone();
|
|
11957
|
+
|
|
11958
|
+
// Add OBJ stats if available
|
|
11959
|
+
if (model.geometryStats) {
|
|
11960
|
+
if (!_clonedModel.userData) {
|
|
11961
|
+
_clonedModel.userData = {};
|
|
11962
|
+
}
|
|
11963
|
+
_clonedModel.userData.geometryStats = model.geometryStats;
|
|
11964
|
+
_clonedModel.userData.isObjModel = true;
|
|
11965
|
+
}
|
|
11966
|
+
} else {
|
|
11967
|
+
// Handle regular GLB models
|
|
11968
|
+
_clonedModel = model.clone();
|
|
11969
|
+
}
|
|
10694
11970
|
|
|
10695
11971
|
// Add dimensions if available
|
|
10696
11972
|
if (componentData.boundingBox) {
|
|
@@ -10726,13 +12002,15 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
10726
12002
|
totalModels: this.modelCache.size,
|
|
10727
12003
|
loadingModels: this.loadingPromises.size,
|
|
10728
12004
|
isPreloading: this.isPreloading,
|
|
10729
|
-
memoryUsage: 0
|
|
12005
|
+
memoryUsage: 0,
|
|
12006
|
+
objProcessorStats: this.objProcessor.getStatus()
|
|
10730
12007
|
};
|
|
10731
12008
|
|
|
10732
12009
|
// Estimate memory usage (rough calculation)
|
|
10733
12010
|
this.modelCache.forEach(function (model) {
|
|
10734
12011
|
if (model && model.traverse) {
|
|
10735
|
-
model.
|
|
12012
|
+
var modelToAnalyze = model.isObjModel ? model.originalObject : model;
|
|
12013
|
+
modelToAnalyze.traverse(function (child) {
|
|
10736
12014
|
if (child.geometry) {
|
|
10737
12015
|
var _child$geometry$attri;
|
|
10738
12016
|
stats.memoryUsage += (((_child$geometry$attri = child.geometry.attributes.position) === null || _child$geometry$attri === void 0 ? void 0 : _child$geometry$attri.count) || 0) * 12; // Rough estimate
|
|
@@ -10742,6 +12020,124 @@ var ModelPreloader = /*#__PURE__*/function () {
|
|
|
10742
12020
|
});
|
|
10743
12021
|
return stats;
|
|
10744
12022
|
}
|
|
12023
|
+
|
|
12024
|
+
/**
|
|
12025
|
+
* Get all OBJ geometry statistics
|
|
12026
|
+
* @returns {Array} Array of OBJ geometry statistics
|
|
12027
|
+
*/
|
|
12028
|
+
}, {
|
|
12029
|
+
key: "getObjGeometryStats",
|
|
12030
|
+
value: function getObjGeometryStats() {
|
|
12031
|
+
return this.objProcessor.getAllGeometryStats();
|
|
12032
|
+
}
|
|
12033
|
+
|
|
12034
|
+
/**
|
|
12035
|
+
* Get OBJ processor memory usage
|
|
12036
|
+
* @returns {Object} Memory usage statistics
|
|
12037
|
+
*/
|
|
12038
|
+
}, {
|
|
12039
|
+
key: "getObjMemoryUsage",
|
|
12040
|
+
value: function getObjMemoryUsage() {
|
|
12041
|
+
return this.objProcessor.getMemoryUsage();
|
|
12042
|
+
}
|
|
12043
|
+
|
|
12044
|
+
/**
|
|
12045
|
+
* Create a custom mesh from indexed OBJ geometry
|
|
12046
|
+
* @param {string} modelKey - The model key (must be an OBJ)
|
|
12047
|
+
* @param {THREE.Material} material - Optional material to use
|
|
12048
|
+
* @returns {THREE.Mesh|null} The created mesh or null if not found
|
|
12049
|
+
*/
|
|
12050
|
+
}, {
|
|
12051
|
+
key: "createCustomObjMesh",
|
|
12052
|
+
value: function createCustomObjMesh(modelKey) {
|
|
12053
|
+
var material = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
12054
|
+
return this.objProcessor.createCustomMesh(modelKey, material);
|
|
12055
|
+
}
|
|
12056
|
+
|
|
12057
|
+
/**
|
|
12058
|
+
* Get indexed geometry directly from processor
|
|
12059
|
+
* @param {string} modelKey - The model key
|
|
12060
|
+
* @returns {THREE.BufferGeometry|null} The indexed geometry or null
|
|
12061
|
+
*/
|
|
12062
|
+
}, {
|
|
12063
|
+
key: "getIndexedGeometry",
|
|
12064
|
+
value: function getIndexedGeometry(modelKey) {
|
|
12065
|
+
var result = this.objProcessor.indexedGeometryCache.get(modelKey);
|
|
12066
|
+
return result ? result.geometry.clone() : null;
|
|
12067
|
+
}
|
|
12068
|
+
|
|
12069
|
+
/**
|
|
12070
|
+
* Toggle wireframe visibility on an OBJ model
|
|
12071
|
+
* @param {THREE.Object3D} model - The model to toggle wireframe on
|
|
12072
|
+
* @param {boolean} visible - Whether wireframe should be visible
|
|
12073
|
+
*/
|
|
12074
|
+
}, {
|
|
12075
|
+
key: "toggleWireframe",
|
|
12076
|
+
value: function toggleWireframe(model) {
|
|
12077
|
+
var visible = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
12078
|
+
if (!model) return;
|
|
12079
|
+
model.traverse(function (child) {
|
|
12080
|
+
if (child.userData && child.userData.isWireframeOverlay) {
|
|
12081
|
+
child.visible = visible;
|
|
12082
|
+
}
|
|
12083
|
+
});
|
|
12084
|
+
}
|
|
12085
|
+
|
|
12086
|
+
/**
|
|
12087
|
+
* Update wireframe appearance on an OBJ model
|
|
12088
|
+
* @param {THREE.Object3D} model - The model to update
|
|
12089
|
+
* @param {Object} options - Wireframe options {color, opacity, visible}
|
|
12090
|
+
*/
|
|
12091
|
+
}, {
|
|
12092
|
+
key: "updateWireframeAppearance",
|
|
12093
|
+
value: function updateWireframeAppearance(model) {
|
|
12094
|
+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
12095
|
+
if (!model) return;
|
|
12096
|
+
var _options$color = options.color,
|
|
12097
|
+
color = _options$color === void 0 ? 0x000000 : _options$color,
|
|
12098
|
+
_options$opacity = options.opacity,
|
|
12099
|
+
opacity = _options$opacity === void 0 ? 0.6 : _options$opacity,
|
|
12100
|
+
_options$visible = options.visible,
|
|
12101
|
+
visible = _options$visible === void 0 ? true : _options$visible;
|
|
12102
|
+
model.traverse(function (child) {
|
|
12103
|
+
if (child.userData && child.userData.isWireframeOverlay && child.material) {
|
|
12104
|
+
child.material.color.setHex(color);
|
|
12105
|
+
child.material.opacity = opacity;
|
|
12106
|
+
child.visible = visible;
|
|
12107
|
+
}
|
|
12108
|
+
});
|
|
12109
|
+
}
|
|
12110
|
+
|
|
12111
|
+
/**
|
|
12112
|
+
* Force reload and reprocess an OBJ model
|
|
12113
|
+
* @param {string} modelKey - The model key to reload
|
|
12114
|
+
* @returns {Promise} Promise that resolves with the reloaded model
|
|
12115
|
+
*/
|
|
12116
|
+
}, {
|
|
12117
|
+
key: "reloadObjModel",
|
|
12118
|
+
value: (function () {
|
|
12119
|
+
var _reloadObjModel = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5(modelKey) {
|
|
12120
|
+
return _regenerator().w(function (_context5) {
|
|
12121
|
+
while (1) switch (_context5.n) {
|
|
12122
|
+
case 0:
|
|
12123
|
+
console.log("\uD83D\uDD04 Force reloading OBJ model: ".concat(modelKey));
|
|
12124
|
+
|
|
12125
|
+
// Clear from both caches
|
|
12126
|
+
this.modelCache.delete(modelKey);
|
|
12127
|
+
this.loadingPromises.delete(modelKey);
|
|
12128
|
+
this.objProcessor.indexedGeometryCache.delete(modelKey);
|
|
12129
|
+
this.objProcessor.geometrySizeCache.delete(modelKey);
|
|
12130
|
+
|
|
12131
|
+
// Reload with OBJ processing
|
|
12132
|
+
return _context5.a(2, this.preloadSingleModel(modelKey, 'obj'));
|
|
12133
|
+
}
|
|
12134
|
+
}, _callee5, this);
|
|
12135
|
+
}));
|
|
12136
|
+
function reloadObjModel(_x5) {
|
|
12137
|
+
return _reloadObjModel.apply(this, arguments);
|
|
12138
|
+
}
|
|
12139
|
+
return reloadObjModel;
|
|
12140
|
+
}())
|
|
10745
12141
|
}]);
|
|
10746
12142
|
}(); // Create singleton instance
|
|
10747
12143
|
var modelPreloader = new ModelPreloader();
|
|
@@ -35283,6 +36679,250 @@ var testing = /*#__PURE__*/Object.freeze({
|
|
|
35283
36679
|
Testing: Testing
|
|
35284
36680
|
});
|
|
35285
36681
|
|
|
36682
|
+
var ObjProcessingDemo = /*#__PURE__*/function () {
|
|
36683
|
+
function ObjProcessingDemo() {
|
|
36684
|
+
_classCallCheck(this, ObjProcessingDemo);
|
|
36685
|
+
this.objProcessor = new ObjProcessor();
|
|
36686
|
+
this.componentDictionary = null;
|
|
36687
|
+
this.processedResults = new Map();
|
|
36688
|
+
}
|
|
36689
|
+
|
|
36690
|
+
/**
|
|
36691
|
+
* Load component dictionary
|
|
36692
|
+
* @returns {Promise<Object>} Component dictionary
|
|
36693
|
+
*/
|
|
36694
|
+
return _createClass(ObjProcessingDemo, [{
|
|
36695
|
+
key: "loadComponentDictionary",
|
|
36696
|
+
value: (function () {
|
|
36697
|
+
var _loadComponentDictionary = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
36698
|
+
var response, _t;
|
|
36699
|
+
return _regenerator().w(function (_context) {
|
|
36700
|
+
while (1) switch (_context.n) {
|
|
36701
|
+
case 0:
|
|
36702
|
+
_context.p = 0;
|
|
36703
|
+
_context.n = 1;
|
|
36704
|
+
return fetch('/library/component-dictionary.json');
|
|
36705
|
+
case 1:
|
|
36706
|
+
response = _context.v;
|
|
36707
|
+
_context.n = 2;
|
|
36708
|
+
return response.json();
|
|
36709
|
+
case 2:
|
|
36710
|
+
this.componentDictionary = _context.v;
|
|
36711
|
+
return _context.a(2, this.componentDictionary);
|
|
36712
|
+
case 3:
|
|
36713
|
+
_context.p = 3;
|
|
36714
|
+
_t = _context.v;
|
|
36715
|
+
throw _t;
|
|
36716
|
+
case 4:
|
|
36717
|
+
return _context.a(2);
|
|
36718
|
+
}
|
|
36719
|
+
}, _callee, this, [[0, 3]]);
|
|
36720
|
+
}));
|
|
36721
|
+
function loadComponentDictionary() {
|
|
36722
|
+
return _loadComponentDictionary.apply(this, arguments);
|
|
36723
|
+
}
|
|
36724
|
+
return loadComponentDictionary;
|
|
36725
|
+
}()
|
|
36726
|
+
/**
|
|
36727
|
+
* Get all OBJ models from component dictionary
|
|
36728
|
+
* @returns {Array} Array of OBJ model configurations
|
|
36729
|
+
*/
|
|
36730
|
+
)
|
|
36731
|
+
}, {
|
|
36732
|
+
key: "getObjModels",
|
|
36733
|
+
value: function getObjModels() {
|
|
36734
|
+
var _this = this;
|
|
36735
|
+
if (!this.componentDictionary) {
|
|
36736
|
+
return [];
|
|
36737
|
+
}
|
|
36738
|
+
var objModels = [];
|
|
36739
|
+
Object.keys(this.componentDictionary).forEach(function (componentId) {
|
|
36740
|
+
var component = _this.componentDictionary[componentId];
|
|
36741
|
+
if (component.modelType === 'obj') {
|
|
36742
|
+
objModels.push({
|
|
36743
|
+
componentId: componentId,
|
|
36744
|
+
modelKey: component.modelKey,
|
|
36745
|
+
name: component.name,
|
|
36746
|
+
boundingBox: component.boundingBox
|
|
36747
|
+
});
|
|
36748
|
+
}
|
|
36749
|
+
});
|
|
36750
|
+
return objModels;
|
|
36751
|
+
}
|
|
36752
|
+
|
|
36753
|
+
/**
|
|
36754
|
+
* Process all OBJ models and store in IndexedDB
|
|
36755
|
+
* @returns {Promise<Array>} Array of processing results
|
|
36756
|
+
*/
|
|
36757
|
+
}, {
|
|
36758
|
+
key: "processAllObjModels",
|
|
36759
|
+
value: (function () {
|
|
36760
|
+
var _processAllObjModels = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2() {
|
|
36761
|
+
var objModels, processingResults, _iterator, _step, objModel, cachedModelData, result, serializedData, _t3;
|
|
36762
|
+
return _regenerator().w(function (_context2) {
|
|
36763
|
+
while (1) switch (_context2.n) {
|
|
36764
|
+
case 0:
|
|
36765
|
+
if (this.componentDictionary) {
|
|
36766
|
+
_context2.n = 1;
|
|
36767
|
+
break;
|
|
36768
|
+
}
|
|
36769
|
+
_context2.n = 1;
|
|
36770
|
+
return this.loadComponentDictionary();
|
|
36771
|
+
case 1:
|
|
36772
|
+
// Get all OBJ models
|
|
36773
|
+
objModels = this.getObjModels();
|
|
36774
|
+
if (!(objModels.length === 0)) {
|
|
36775
|
+
_context2.n = 2;
|
|
36776
|
+
break;
|
|
36777
|
+
}
|
|
36778
|
+
return _context2.a(2, []);
|
|
36779
|
+
case 2:
|
|
36780
|
+
_context2.n = 3;
|
|
36781
|
+
return modelPreloader.preloadAllModels(this.componentDictionary);
|
|
36782
|
+
case 3:
|
|
36783
|
+
if (!this.objProcessor.idbSupported) {
|
|
36784
|
+
_context2.n = 4;
|
|
36785
|
+
break;
|
|
36786
|
+
}
|
|
36787
|
+
_context2.n = 4;
|
|
36788
|
+
return this.objProcessor.initializeIDB();
|
|
36789
|
+
case 4:
|
|
36790
|
+
processingResults = []; // Process each OBJ model
|
|
36791
|
+
_iterator = _createForOfIteratorHelper(objModels);
|
|
36792
|
+
_context2.p = 5;
|
|
36793
|
+
_iterator.s();
|
|
36794
|
+
case 6:
|
|
36795
|
+
if ((_step = _iterator.n()).done) {
|
|
36796
|
+
_context2.n = 12;
|
|
36797
|
+
break;
|
|
36798
|
+
}
|
|
36799
|
+
objModel = _step.value;
|
|
36800
|
+
_context2.p = 7;
|
|
36801
|
+
// Get the cached model from preloader
|
|
36802
|
+
cachedModelData = modelPreloader.modelCache.get(objModel.modelKey);
|
|
36803
|
+
if (!(!cachedModelData || !cachedModelData.isObjModel)) {
|
|
36804
|
+
_context2.n = 8;
|
|
36805
|
+
break;
|
|
36806
|
+
}
|
|
36807
|
+
return _context2.a(3, 11);
|
|
36808
|
+
case 8:
|
|
36809
|
+
// Extract processing results
|
|
36810
|
+
result = {
|
|
36811
|
+
componentId: objModel.componentId,
|
|
36812
|
+
modelKey: objModel.modelKey,
|
|
36813
|
+
name: objModel.name,
|
|
36814
|
+
boundingBox: objModel.boundingBox,
|
|
36815
|
+
stats: cachedModelData.geometryStats,
|
|
36816
|
+
originalObject: cachedModelData.originalObject,
|
|
36817
|
+
processedGeometry: cachedModelData.processedGeometry,
|
|
36818
|
+
materials: cachedModelData.materials
|
|
36819
|
+
};
|
|
36820
|
+
processingResults.push(result);
|
|
36821
|
+
this.processedResults.set(objModel.modelKey, result);
|
|
36822
|
+
|
|
36823
|
+
// Store in IndexedDB if supported
|
|
36824
|
+
if (!(this.objProcessor.idbSupported && result.processedGeometry)) {
|
|
36825
|
+
_context2.n = 9;
|
|
36826
|
+
break;
|
|
36827
|
+
}
|
|
36828
|
+
serializedData = this.objProcessor.serializeGeometry(result.processedGeometry);
|
|
36829
|
+
_context2.n = 9;
|
|
36830
|
+
return this.objProcessor.storeGeometryInIDB(objModel.modelKey, serializedData);
|
|
36831
|
+
case 9:
|
|
36832
|
+
_context2.n = 11;
|
|
36833
|
+
break;
|
|
36834
|
+
case 10:
|
|
36835
|
+
_context2.p = 10;
|
|
36836
|
+
_context2.v;
|
|
36837
|
+
return _context2.a(3, 11);
|
|
36838
|
+
case 11:
|
|
36839
|
+
_context2.n = 6;
|
|
36840
|
+
break;
|
|
36841
|
+
case 12:
|
|
36842
|
+
_context2.n = 14;
|
|
36843
|
+
break;
|
|
36844
|
+
case 13:
|
|
36845
|
+
_context2.p = 13;
|
|
36846
|
+
_t3 = _context2.v;
|
|
36847
|
+
_iterator.e(_t3);
|
|
36848
|
+
case 14:
|
|
36849
|
+
_context2.p = 14;
|
|
36850
|
+
_iterator.f();
|
|
36851
|
+
return _context2.f(14);
|
|
36852
|
+
case 15:
|
|
36853
|
+
return _context2.a(2, processingResults);
|
|
36854
|
+
}
|
|
36855
|
+
}, _callee2, this, [[7, 10], [5, 13, 14, 15]]);
|
|
36856
|
+
}));
|
|
36857
|
+
function processAllObjModels() {
|
|
36858
|
+
return _processAllObjModels.apply(this, arguments);
|
|
36859
|
+
}
|
|
36860
|
+
return processAllObjModels;
|
|
36861
|
+
}()
|
|
36862
|
+
/**
|
|
36863
|
+
* Run the simplified demo - process and store in IndexedDB
|
|
36864
|
+
* @returns {Promise<Object>} Demo results
|
|
36865
|
+
*/
|
|
36866
|
+
)
|
|
36867
|
+
}, {
|
|
36868
|
+
key: "run",
|
|
36869
|
+
value: (function () {
|
|
36870
|
+
var _run = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
|
|
36871
|
+
var processingResults, _t4;
|
|
36872
|
+
return _regenerator().w(function (_context3) {
|
|
36873
|
+
while (1) switch (_context3.n) {
|
|
36874
|
+
case 0:
|
|
36875
|
+
_context3.p = 0;
|
|
36876
|
+
_context3.n = 1;
|
|
36877
|
+
return this.processAllObjModels();
|
|
36878
|
+
case 1:
|
|
36879
|
+
processingResults = _context3.v;
|
|
36880
|
+
return _context3.a(2, {
|
|
36881
|
+
processingResults: processingResults,
|
|
36882
|
+
totalModelsProcessed: processingResults.length,
|
|
36883
|
+
success: true
|
|
36884
|
+
});
|
|
36885
|
+
case 2:
|
|
36886
|
+
_context3.p = 2;
|
|
36887
|
+
_t4 = _context3.v;
|
|
36888
|
+
return _context3.a(2, {
|
|
36889
|
+
processingResults: [],
|
|
36890
|
+
totalModelsProcessed: 0,
|
|
36891
|
+
success: false,
|
|
36892
|
+
error: _t4.message
|
|
36893
|
+
});
|
|
36894
|
+
}
|
|
36895
|
+
}, _callee3, this, [[0, 2]]);
|
|
36896
|
+
}));
|
|
36897
|
+
function run() {
|
|
36898
|
+
return _run.apply(this, arguments);
|
|
36899
|
+
}
|
|
36900
|
+
return run;
|
|
36901
|
+
}()
|
|
36902
|
+
/**
|
|
36903
|
+
* Get processing results for external use
|
|
36904
|
+
* @returns {Map} Map of processing results
|
|
36905
|
+
*/
|
|
36906
|
+
)
|
|
36907
|
+
}, {
|
|
36908
|
+
key: "getResults",
|
|
36909
|
+
value: function getResults() {
|
|
36910
|
+
return this.processedResults;
|
|
36911
|
+
}
|
|
36912
|
+
|
|
36913
|
+
/**
|
|
36914
|
+
* Get geometry by model key
|
|
36915
|
+
* @param {string} modelKey - The model key
|
|
36916
|
+
* @returns {Object|null} Processing result or null
|
|
36917
|
+
*/
|
|
36918
|
+
}, {
|
|
36919
|
+
key: "getGeometry",
|
|
36920
|
+
value: function getGeometry(modelKey) {
|
|
36921
|
+
return this.processedResults.get(modelKey) || null;
|
|
36922
|
+
}
|
|
36923
|
+
}]);
|
|
36924
|
+
}(); // Export for use
|
|
36925
|
+
|
|
35286
36926
|
exports.Analysis = analysis;
|
|
35287
36927
|
exports.AnimationManager = AnimationManager;
|
|
35288
36928
|
exports.CameraControlsManager = CameraControlsManager;
|
|
@@ -35298,6 +36938,8 @@ exports.ImportUtils = _import;
|
|
|
35298
36938
|
exports.KeyboardControlsManager = KeyboardControlsManager;
|
|
35299
36939
|
exports.MathUtils = MathUtils;
|
|
35300
36940
|
exports.Numerics = numerics;
|
|
36941
|
+
exports.ObjProcessingDemo = ObjProcessingDemo;
|
|
36942
|
+
exports.ObjProcessor = ObjProcessor;
|
|
35301
36943
|
exports.PathfindingManager = PathfindingManager;
|
|
35302
36944
|
exports.PerformanceMonitor = PerformanceMonitor;
|
|
35303
36945
|
exports.Rendering2D = rendering2D;
|