@2112-lab/central-plant 0.1.13 → 0.1.15

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.
@@ -6,6 +6,7 @@ var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelper
6
6
  var THREE = require('three');
7
7
  var GLTFLoader = require('../../node_modules/three/examples/jsm/loaders/GLTFLoader.js');
8
8
  var OBJLoader = require('../../node_modules/three/examples/jsm/loaders/OBJLoader.js');
9
+ var objProcessor = require('./objProcessor.js');
9
10
 
10
11
  function _interopNamespace(e) {
11
12
  if (e && e.__esModule) return e;
@@ -34,10 +35,12 @@ var ModelPreloader = /*#__PURE__*/function () {
34
35
  this.loadingPromises = new Map(); // Track ongoing loads to prevent duplicates
35
36
  this.gltfLoader = new GLTFLoader.GLTFLoader();
36
37
  this.objLoader = new OBJLoader.OBJLoader();
38
+ this.objProcessor = new objProcessor["default"](); // Initialize OBJ processor
37
39
  this.isPreloading = false;
38
40
  this.preloadingPromise = null;
39
41
  this.componentDictionary = null;
40
42
  console.log('🚀 ModelPreloader initialized with GLB and OBJ support');
43
+ console.log('🔧 OBJ Processor integrated for indexed BufferGeometry conversion');
41
44
  }
42
45
 
43
46
  /**
@@ -143,93 +146,110 @@ var ModelPreloader = /*#__PURE__*/function () {
143
146
  }, {
144
147
  key: "preloadSingleModel",
145
148
  value: (function () {
146
- var _preloadSingleModel = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee2(modelKey) {
149
+ var _preloadSingleModel = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee3(modelKey) {
147
150
  var _this2 = this;
148
151
  var modelType,
149
152
  loadPromise,
150
- _args2 = arguments;
151
- return _rollupPluginBabelHelpers.regenerator().w(function (_context2) {
152
- while (1) switch (_context2.n) {
153
+ _args3 = arguments;
154
+ return _rollupPluginBabelHelpers.regenerator().w(function (_context3) {
155
+ while (1) switch (_context3.n) {
153
156
  case 0:
154
- modelType = _args2.length > 1 && _args2[1] !== undefined ? _args2[1] : 'glb';
157
+ modelType = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : 'glb';
155
158
  if (!this.modelCache.has(modelKey)) {
156
- _context2.n = 1;
159
+ _context3.n = 1;
157
160
  break;
158
161
  }
159
162
  console.log("\uD83C\uDFAF Model ".concat(modelKey, " already cached, skipping"));
160
- return _context2.a(2, this.modelCache.get(modelKey));
163
+ return _context3.a(2, this.modelCache.get(modelKey));
161
164
  case 1:
162
165
  if (!this.loadingPromises.has(modelKey)) {
163
- _context2.n = 2;
166
+ _context3.n = 2;
164
167
  break;
165
168
  }
166
169
  console.log("\u23F3 Model ".concat(modelKey, " already loading, waiting for completion"));
167
- return _context2.a(2, this.loadingPromises.get(modelKey));
170
+ return _context3.a(2, this.loadingPromises.get(modelKey));
168
171
  case 2:
169
172
  console.log("\uD83D\uDD04 Starting preload of ".concat(modelType.toUpperCase(), " model: ").concat(modelKey));
170
173
  loadPromise = new Promise(function (resolve, reject) {
171
174
  var modelPath = "/library/models/".concat(modelKey);
172
175
  if (modelType === 'obj') {
173
- // Load OBJ model
174
- _this2.objLoader.load(modelPath, function (object) {
175
- console.log("\u2705 Successfully preloaded OBJ model: ".concat(modelKey));
176
-
177
- // Apply double-sided materials to OBJ models with both solid and wireframe
178
- object.traverse(function (child) {
179
- if (child.isMesh) {
180
- // Create a solid material first
181
- var solidMaterial = new THREE__namespace.MeshStandardMaterial({
182
- color: child.material.color || 0x888888,
183
- side: THREE__namespace.DoubleSide,
184
- wireframe: false
185
- });
186
-
187
- // Set the solid material
188
- child.material = solidMaterial;
189
-
190
- // Create wireframe overlay by cloning the geometry
191
- var wireframeGeometry = child.geometry.clone();
192
- var wireframeMaterial = new THREE__namespace.MeshBasicMaterial({
193
- color: 0x000000,
194
- wireframe: true,
195
- transparent: true,
196
- opacity: 0.8
197
- });
198
-
199
- // Create wireframe mesh with same geometry
200
- var wireframeMesh = new THREE__namespace.Mesh(wireframeGeometry, wireframeMaterial);
201
- wireframeMesh.name = child.name + '_wireframe';
202
-
203
- // Position wireframe slightly forward to avoid z-fighting
204
- wireframeMesh.position.copy(child.position);
205
- wireframeMesh.rotation.copy(child.rotation);
206
- wireframeMesh.scale.copy(child.scale);
207
- wireframeMesh.scale.multiplyScalar(1.001); // Slightly larger to sit on top
208
-
209
- // Add wireframe as sibling to the parent
210
- if (child.parent) {
211
- child.parent.add(wireframeMesh);
176
+ // Load OBJ model with advanced processing
177
+ _this2.objLoader.load(modelPath, /*#__PURE__*/function () {
178
+ var _ref = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee2(object) {
179
+ var processedResult, modelData, _t;
180
+ return _rollupPluginBabelHelpers.regenerator().w(function (_context2) {
181
+ while (1) switch (_context2.n) {
182
+ case 0:
183
+ _context2.p = 0;
184
+ console.log("\u2705 Successfully loaded OBJ model: ".concat(modelKey));
185
+
186
+ // Process OBJ with the new processor for indexed BufferGeometry
187
+ _context2.n = 1;
188
+ return _this2.objProcessor.processObjObject(object, modelKey, true);
189
+ case 1:
190
+ processedResult = _context2.v;
191
+ if (!processedResult) {
192
+ _context2.n = 2;
193
+ break;
194
+ }
195
+ console.log("\uD83D\uDD27 OBJ processed to indexed BufferGeometry: ".concat(modelKey));
196
+ console.log("\uD83D\uDCCA Geometry stats:", processedResult.stats);
197
+
198
+ // Apply double-sided materials to original OBJ for compatibility
199
+ object.traverse(function (child) {
200
+ if (child.isMesh) {
201
+ var solidMaterial = new THREE__namespace.MeshStandardMaterial({
202
+ color: child.material.color || 0x888888,
203
+ side: THREE__namespace.DoubleSide,
204
+ wireframe: false
205
+ });
206
+ child.material = solidMaterial;
207
+ }
208
+ });
209
+
210
+ // Store both the original object and processed data
211
+ modelData = {
212
+ originalObject: object,
213
+ processedGeometry: processedResult.geometry,
214
+ geometryStats: processedResult.stats,
215
+ materials: processedResult.materials,
216
+ isObjModel: true
217
+ }; // Cache the model data
218
+ _this2.modelCache.set(modelKey, modelData);
219
+ _this2.loadingPromises.delete(modelKey);
220
+ resolve(modelData);
221
+ _context2.n = 3;
222
+ break;
223
+ case 2:
224
+ throw new Error('Failed to process OBJ to indexed geometry');
225
+ case 3:
226
+ _context2.n = 5;
227
+ break;
228
+ case 4:
229
+ _context2.p = 4;
230
+ _t = _context2.v;
231
+ console.error("\u274C Error processing OBJ model ".concat(modelKey, ":"), _t);
232
+ // Fallback: cache the original object without processing
233
+ _this2.modelCache.set(modelKey, object);
234
+ _this2.loadingPromises.delete(modelKey);
235
+ resolve(object);
236
+ case 5:
237
+ return _context2.a(2);
212
238
  }
213
- }
214
- });
215
-
216
- // Cache the object for future use
217
- _this2.modelCache.set(modelKey, object);
218
- // Remove from loading promises
219
- _this2.loadingPromises.delete(modelKey);
220
- resolve(object);
221
- }, function (progress) {
222
- // Optional: track loading progress
239
+ }, _callee2, null, [[0, 4]]);
240
+ }));
241
+ return function (_x3) {
242
+ return _ref.apply(this, arguments);
243
+ };
244
+ }(), function (progress) {
223
245
  if (progress.lengthComputable) {
224
246
  var percentage = progress.loaded / progress.total * 100;
225
247
  if (percentage % 25 === 0) {
226
- // Log every 25%
227
248
  console.log("\uD83D\uDCCA Loading OBJ ".concat(modelKey, ": ").concat(percentage.toFixed(0), "%"));
228
249
  }
229
250
  }
230
251
  }, function (error) {
231
252
  console.error("\u274C Failed to preload OBJ model ".concat(modelKey, ":"), error);
232
- // Remove from loading promises
233
253
  _this2.loadingPromises.delete(modelKey);
234
254
  reject(error);
235
255
  });
@@ -260,9 +280,9 @@ var ModelPreloader = /*#__PURE__*/function () {
260
280
  }
261
281
  }); // Cache the loading promise
262
282
  this.loadingPromises.set(modelKey, loadPromise);
263
- return _context2.a(2, loadPromise);
283
+ return _context3.a(2, loadPromise);
264
284
  }
265
- }, _callee2, this);
285
+ }, _callee3, this);
266
286
  }));
267
287
  function preloadSingleModel(_x2) {
268
288
  return _preloadSingleModel.apply(this, arguments);
@@ -272,18 +292,42 @@ var ModelPreloader = /*#__PURE__*/function () {
272
292
  /**
273
293
  * Get a cached model (cloned for use)
274
294
  * @param {string} modelKey - The model key
295
+ * @param {boolean} useIndexedGeometry - Whether to use indexed geometry for OBJ models
275
296
  * @returns {THREE.Object3D|null} Cloned model or null if not found
276
297
  */
277
298
  )
278
299
  }, {
279
300
  key: "getCachedModel",
280
301
  value: function getCachedModel(modelKey) {
302
+ var useIndexedGeometry = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
281
303
  if (this.modelCache.has(modelKey)) {
282
304
  console.log("\uD83C\uDFAF Returning cached model: ".concat(modelKey));
283
- var clonedModel = this.modelCache.get(modelKey).clone();
305
+ var cachedData = this.modelCache.get(modelKey);
306
+
307
+ // Handle OBJ models with processed geometry
308
+ if (cachedData && cachedData.isObjModel && useIndexedGeometry && cachedData.processedGeometry) {
309
+ console.log("\uD83D\uDD27 Using indexed BufferGeometry for OBJ: ".concat(modelKey));
310
+
311
+ // Create a mesh from the processed indexed geometry
312
+ var mesh = new THREE__namespace.Mesh(cachedData.processedGeometry.clone(), cachedData.materials.clone());
313
+
314
+ // Add metadata
315
+ mesh.userData.modelKey = modelKey;
316
+ mesh.userData.geometryStats = cachedData.geometryStats;
317
+ mesh.userData.isIndexedGeometry = true;
318
+ mesh.userData.originalSizeKB = cachedData.geometryStats.sizeKB;
319
+ return mesh;
320
+ }
321
+
322
+ // Handle regular models or OBJ models without indexed geometry
323
+ var modelToClone = cachedData.isObjModel ? cachedData.originalObject : cachedData;
324
+ var clonedModel = modelToClone.clone();
284
325
 
285
- // Determine model type from the modelKey extension
286
- modelKey.toLowerCase().endsWith('.obj') ? 'obj' : 'glb';
326
+ // Add OBJ stats if available
327
+ if (cachedData.isObjModel && cachedData.geometryStats) {
328
+ clonedModel.userData.geometryStats = cachedData.geometryStats;
329
+ clonedModel.userData.isObjModel = true;
330
+ }
287
331
  return clonedModel;
288
332
  }
289
333
  console.warn("\u26A0\uFE0F Model ".concat(modelKey, " not found in cache"));
@@ -391,41 +435,41 @@ var ModelPreloader = /*#__PURE__*/function () {
391
435
  }, {
392
436
  key: "reloadModel",
393
437
  value: (function () {
394
- var _reloadModel = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee3(modelKey) {
438
+ var _reloadModel = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee4(modelKey) {
395
439
  var modelType,
396
440
  _i,
397
441
  _Object$keys,
398
442
  componentType,
399
443
  component,
400
- _args3 = arguments;
401
- return _rollupPluginBabelHelpers.regenerator().w(function (_context3) {
402
- while (1) switch (_context3.n) {
444
+ _args4 = arguments;
445
+ return _rollupPluginBabelHelpers.regenerator().w(function (_context4) {
446
+ while (1) switch (_context4.n) {
403
447
  case 0:
404
- modelType = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : null;
448
+ modelType = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : null;
405
449
  console.log("\uD83D\uDD04 Force reloading model: ".concat(modelKey));
406
450
 
407
451
  // Try to determine model type from component dictionary if not provided
408
452
  if (!(!modelType && this.componentDictionary)) {
409
- _context3.n = 3;
453
+ _context4.n = 3;
410
454
  break;
411
455
  }
412
456
  _i = 0, _Object$keys = Object.keys(this.componentDictionary);
413
457
  case 1:
414
458
  if (!(_i < _Object$keys.length)) {
415
- _context3.n = 3;
459
+ _context4.n = 3;
416
460
  break;
417
461
  }
418
462
  componentType = _Object$keys[_i];
419
463
  component = this.componentDictionary[componentType];
420
464
  if (!(component && component.modelKey === modelKey)) {
421
- _context3.n = 2;
465
+ _context4.n = 2;
422
466
  break;
423
467
  }
424
468
  modelType = component.modelType || 'glb';
425
- return _context3.a(3, 3);
469
+ return _context4.a(3, 3);
426
470
  case 2:
427
471
  _i++;
428
- _context3.n = 1;
472
+ _context4.n = 1;
429
473
  break;
430
474
  case 3:
431
475
  // Default to GLB if still not determined
@@ -436,11 +480,11 @@ var ModelPreloader = /*#__PURE__*/function () {
436
480
  this.loadingPromises.delete(modelKey);
437
481
 
438
482
  // Preload again
439
- return _context3.a(2, this.preloadSingleModel(modelKey, modelType));
483
+ return _context4.a(2, this.preloadSingleModel(modelKey, modelType));
440
484
  }
441
- }, _callee3, this);
485
+ }, _callee4, this);
442
486
  }));
443
- function reloadModel(_x3) {
487
+ function reloadModel(_x4) {
444
488
  return _reloadModel.apply(this, arguments);
445
489
  }
446
490
  return reloadModel;
@@ -457,7 +501,42 @@ var ModelPreloader = /*#__PURE__*/function () {
457
501
  // Dispose of all cached models
458
502
  this.modelCache.forEach(function (model, modelKey) {
459
503
  console.log("\uD83D\uDDD1\uFE0F Disposing cached model: ".concat(modelKey));
460
- if (model && model.traverse) {
504
+ if (model && model.isObjModel) {
505
+ // Handle OBJ model data structure
506
+ if (model.originalObject && model.originalObject.traverse) {
507
+ model.originalObject.traverse(function (child) {
508
+ if (child.geometry) {
509
+ child.geometry.dispose();
510
+ }
511
+ if (child.material) {
512
+ if (Array.isArray(child.material)) {
513
+ child.material.forEach(function (material) {
514
+ return material.dispose();
515
+ });
516
+ } else {
517
+ child.material.dispose();
518
+ }
519
+ }
520
+ });
521
+ }
522
+
523
+ // Dispose processed geometry
524
+ if (model.processedGeometry) {
525
+ model.processedGeometry.dispose();
526
+ }
527
+
528
+ // Dispose materials
529
+ if (model.materials) {
530
+ if (Array.isArray(model.materials)) {
531
+ model.materials.forEach(function (material) {
532
+ return material.dispose();
533
+ });
534
+ } else {
535
+ model.materials.dispose();
536
+ }
537
+ }
538
+ } else if (model && model.traverse) {
539
+ // Handle regular model
461
540
  model.traverse(function (child) {
462
541
  if (child.geometry) {
463
542
  child.geometry.dispose();
@@ -478,6 +557,9 @@ var ModelPreloader = /*#__PURE__*/function () {
478
557
  this.loadingPromises.clear();
479
558
  this.isPreloading = false;
480
559
  this.preloadingPromise = null;
560
+
561
+ // Clear OBJ processor caches
562
+ this.objProcessor.clearCaches();
481
563
  console.log('✅ Model preloader cache cleared');
482
564
  }
483
565
 
@@ -586,13 +668,15 @@ var ModelPreloader = /*#__PURE__*/function () {
586
668
  totalModels: this.modelCache.size,
587
669
  loadingModels: this.loadingPromises.size,
588
670
  isPreloading: this.isPreloading,
589
- memoryUsage: 0
671
+ memoryUsage: 0,
672
+ objProcessorStats: this.objProcessor.getStatus()
590
673
  };
591
674
 
592
675
  // Estimate memory usage (rough calculation)
593
676
  this.modelCache.forEach(function (model) {
594
677
  if (model && model.traverse) {
595
- model.traverse(function (child) {
678
+ var modelToAnalyze = model.isObjModel ? model.originalObject : model;
679
+ modelToAnalyze.traverse(function (child) {
596
680
  if (child.geometry) {
597
681
  var _child$geometry$attri;
598
682
  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
@@ -602,6 +686,82 @@ var ModelPreloader = /*#__PURE__*/function () {
602
686
  });
603
687
  return stats;
604
688
  }
689
+
690
+ /**
691
+ * Get all OBJ geometry statistics
692
+ * @returns {Array} Array of OBJ geometry statistics
693
+ */
694
+ }, {
695
+ key: "getObjGeometryStats",
696
+ value: function getObjGeometryStats() {
697
+ return this.objProcessor.getAllGeometryStats();
698
+ }
699
+
700
+ /**
701
+ * Get OBJ processor memory usage
702
+ * @returns {Object} Memory usage statistics
703
+ */
704
+ }, {
705
+ key: "getObjMemoryUsage",
706
+ value: function getObjMemoryUsage() {
707
+ return this.objProcessor.getMemoryUsage();
708
+ }
709
+
710
+ /**
711
+ * Create a custom mesh from indexed OBJ geometry
712
+ * @param {string} modelKey - The model key (must be an OBJ)
713
+ * @param {THREE.Material} material - Optional material to use
714
+ * @returns {THREE.Mesh|null} The created mesh or null if not found
715
+ */
716
+ }, {
717
+ key: "createCustomObjMesh",
718
+ value: function createCustomObjMesh(modelKey) {
719
+ var material = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
720
+ return this.objProcessor.createCustomMesh(modelKey, material);
721
+ }
722
+
723
+ /**
724
+ * Get indexed geometry directly from processor
725
+ * @param {string} modelKey - The model key
726
+ * @returns {THREE.BufferGeometry|null} The indexed geometry or null
727
+ */
728
+ }, {
729
+ key: "getIndexedGeometry",
730
+ value: function getIndexedGeometry(modelKey) {
731
+ var result = this.objProcessor.indexedGeometryCache.get(modelKey);
732
+ return result ? result.geometry.clone() : null;
733
+ }
734
+
735
+ /**
736
+ * Force reload and reprocess an OBJ model
737
+ * @param {string} modelKey - The model key to reload
738
+ * @returns {Promise} Promise that resolves with the reloaded model
739
+ */
740
+ }, {
741
+ key: "reloadObjModel",
742
+ value: (function () {
743
+ var _reloadObjModel = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee5(modelKey) {
744
+ return _rollupPluginBabelHelpers.regenerator().w(function (_context5) {
745
+ while (1) switch (_context5.n) {
746
+ case 0:
747
+ console.log("\uD83D\uDD04 Force reloading OBJ model: ".concat(modelKey));
748
+
749
+ // Clear from both caches
750
+ this.modelCache.delete(modelKey);
751
+ this.loadingPromises.delete(modelKey);
752
+ this.objProcessor.indexedGeometryCache.delete(modelKey);
753
+ this.objProcessor.geometrySizeCache.delete(modelKey);
754
+
755
+ // Reload with OBJ processing
756
+ return _context5.a(2, this.preloadSingleModel(modelKey, 'obj'));
757
+ }
758
+ }, _callee5, this);
759
+ }));
760
+ function reloadObjModel(_x5) {
761
+ return _reloadObjModel.apply(this, arguments);
762
+ }
763
+ return reloadObjModel;
764
+ }())
605
765
  }]);
606
766
  }(); // Create singleton instance
607
767
  var modelPreloader = new ModelPreloader();