@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.
- package/dist/bundle/index.js +1619 -82
- 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 +241 -81
- 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 +241 -81
- package/dist/esm/src/rendering/objProcessor.js +678 -0
- package/dist/esm/src/testing/objProcessingDemo.js +249 -0
- package/package.json +1 -1
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
import { createClass as _createClass, classCallCheck as _classCallCheck, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
|
+
import * as THREE from 'three';
|
|
3
|
+
import { mergeGeometries, mergeVertices } from '../../node_modules/three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
4
|
+
|
|
5
|
+
var ObjProcessor = /*#__PURE__*/function () {
|
|
6
|
+
function ObjProcessor() {
|
|
7
|
+
_classCallCheck(this, ObjProcessor);
|
|
8
|
+
this.indexedGeometryCache = new Map(); // Cache for indexed geometries
|
|
9
|
+
this.geometrySizeCache = new Map(); // Cache for geometry sizes
|
|
10
|
+
this.idbSupported = this.checkIndexedDBSupport();
|
|
11
|
+
this.dbName = 'CentralPlantGeometryDB';
|
|
12
|
+
this.dbVersion = 1;
|
|
13
|
+
this.storeName = 'indexedGeometries';
|
|
14
|
+
console.log('๐ง ObjProcessor initialized');
|
|
15
|
+
console.log("\uD83D\uDCE6 IndexedDB supported: ".concat(this.idbSupported));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Check if IndexedDB is supported
|
|
20
|
+
* @returns {boolean} True if IndexedDB is supported
|
|
21
|
+
*/
|
|
22
|
+
return _createClass(ObjProcessor, [{
|
|
23
|
+
key: "checkIndexedDBSupport",
|
|
24
|
+
value: function checkIndexedDBSupport() {
|
|
25
|
+
if (typeof window === 'undefined') return false;
|
|
26
|
+
return 'indexedDB' in window && window.indexedDB !== null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Initialize IndexedDB for geometry storage
|
|
31
|
+
* @returns {Promise<IDBDatabase>} Promise that resolves to the database
|
|
32
|
+
*/
|
|
33
|
+
}, {
|
|
34
|
+
key: "initializeIDB",
|
|
35
|
+
value: (function () {
|
|
36
|
+
var _initializeIDB = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
|
|
37
|
+
var _this = this;
|
|
38
|
+
return _regenerator().w(function (_context) {
|
|
39
|
+
while (1) switch (_context.n) {
|
|
40
|
+
case 0:
|
|
41
|
+
if (this.idbSupported) {
|
|
42
|
+
_context.n = 1;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
throw new Error('IndexedDB not supported');
|
|
46
|
+
case 1:
|
|
47
|
+
return _context.a(2, new Promise(function (resolve, reject) {
|
|
48
|
+
var request = indexedDB.open(_this.dbName, _this.dbVersion);
|
|
49
|
+
request.onerror = function () {
|
|
50
|
+
console.error('โ Failed to open IndexedDB');
|
|
51
|
+
reject(request.error);
|
|
52
|
+
};
|
|
53
|
+
request.onsuccess = function () {
|
|
54
|
+
console.log('โ
IndexedDB opened successfully');
|
|
55
|
+
resolve(request.result);
|
|
56
|
+
};
|
|
57
|
+
request.onupgradeneeded = function (event) {
|
|
58
|
+
console.log('๐ Upgrading IndexedDB schema');
|
|
59
|
+
var db = event.target.result;
|
|
60
|
+
|
|
61
|
+
// Create object store for indexed geometries
|
|
62
|
+
if (!db.objectStoreNames.contains(_this.storeName)) {
|
|
63
|
+
var store = db.createObjectStore(_this.storeName, {
|
|
64
|
+
keyPath: 'modelKey'
|
|
65
|
+
});
|
|
66
|
+
store.createIndex('modelType', 'modelType', {
|
|
67
|
+
unique: false
|
|
68
|
+
});
|
|
69
|
+
store.createIndex('sizeKB', 'sizeKB', {
|
|
70
|
+
unique: false
|
|
71
|
+
});
|
|
72
|
+
console.log('๐ฆ Created geometry object store');
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}));
|
|
76
|
+
}
|
|
77
|
+
}, _callee, this);
|
|
78
|
+
}));
|
|
79
|
+
function initializeIDB() {
|
|
80
|
+
return _initializeIDB.apply(this, arguments);
|
|
81
|
+
}
|
|
82
|
+
return initializeIDB;
|
|
83
|
+
}()
|
|
84
|
+
/**
|
|
85
|
+
* Convert OBJ object to indexed BufferGeometry
|
|
86
|
+
* @param {THREE.Object3D} objObject - The loaded OBJ object from THREE.OBJLoader
|
|
87
|
+
* @param {string} modelKey - The model key for identification
|
|
88
|
+
* @returns {Object} Object containing indexed geometry and metadata
|
|
89
|
+
*/
|
|
90
|
+
)
|
|
91
|
+
}, {
|
|
92
|
+
key: "objToIndexedBufferGeometry",
|
|
93
|
+
value: function objToIndexedBufferGeometry(objObject, modelKey) {
|
|
94
|
+
var _this2 = this;
|
|
95
|
+
console.log("\uD83D\uDD04 Converting OBJ to indexed BufferGeometry: ".concat(modelKey));
|
|
96
|
+
var geometries = [];
|
|
97
|
+
var materials = [];
|
|
98
|
+
|
|
99
|
+
// Traverse the OBJ object and collect all geometries
|
|
100
|
+
objObject.traverse(function (child) {
|
|
101
|
+
if (child.isMesh && child.geometry) {
|
|
102
|
+
// Clone the geometry to avoid modifying the original
|
|
103
|
+
var geometry = child.geometry.clone();
|
|
104
|
+
|
|
105
|
+
// Ensure the geometry has proper attributes
|
|
106
|
+
if (!geometry.attributes.position) {
|
|
107
|
+
console.warn("\u26A0\uFE0F Geometry missing position attribute: ".concat(modelKey));
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Compute normals if missing
|
|
112
|
+
if (!geometry.attributes.normal) {
|
|
113
|
+
geometry.computeVertexNormals();
|
|
114
|
+
console.log("\uD83D\uDCD0 Computed normals for geometry: ".concat(modelKey));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Compute UVs if missing (simple planar mapping)
|
|
118
|
+
if (!geometry.attributes.uv) {
|
|
119
|
+
_this2.computeSimpleUVs(geometry);
|
|
120
|
+
console.log("\uD83D\uDDFA\uFE0F Computed UVs for geometry: ".concat(modelKey));
|
|
121
|
+
}
|
|
122
|
+
geometries.push(geometry);
|
|
123
|
+
materials.push(child.material);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
if (geometries.length === 0) {
|
|
127
|
+
console.warn("\u26A0\uFE0F No valid geometries found in OBJ: ".concat(modelKey));
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Merge all geometries into one
|
|
132
|
+
var mergedGeometry;
|
|
133
|
+
if (geometries.length === 1) {
|
|
134
|
+
mergedGeometry = geometries[0];
|
|
135
|
+
} else {
|
|
136
|
+
console.log("\uD83D\uDD17 Merging ".concat(geometries.length, " geometries for: ").concat(modelKey));
|
|
137
|
+
mergedGeometry = mergeGeometries(geometries);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Convert to indexed geometry if not already indexed
|
|
141
|
+
var indexedGeometry = mergedGeometry;
|
|
142
|
+
var originalGeometry = mergedGeometry; // Keep reference to original for comparison
|
|
143
|
+
|
|
144
|
+
if (!mergedGeometry.index) {
|
|
145
|
+
console.log("\uD83D\uDCCA Converting to indexed geometry: ".concat(modelKey));
|
|
146
|
+
indexedGeometry = mergeVertices(mergedGeometry);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Calculate geometry statistics with original geometry for comparison
|
|
150
|
+
var stats = this.calculateGeometryStats(indexedGeometry, modelKey, originalGeometry);
|
|
151
|
+
|
|
152
|
+
// Prepare serializable data for storage
|
|
153
|
+
var geometryData = this.serializeGeometry(indexedGeometry, modelKey, stats);
|
|
154
|
+
console.log("\u2705 Successfully converted OBJ to indexed BufferGeometry: ".concat(modelKey));
|
|
155
|
+
console.log("\uD83D\uDCCA Vertices: ".concat(stats.vertexCount, ", Faces: ").concat(stats.faceCount));
|
|
156
|
+
console.log("\uD83D\uDCBE Indexed Size: ".concat(stats.indexedSizeKB, "KB"));
|
|
157
|
+
if (stats.nonIndexedSizeKB > 0) {
|
|
158
|
+
console.log("\uD83D\uDCBE Non-Indexed Size: ".concat(stats.nonIndexedSizeKB, "KB"));
|
|
159
|
+
console.log("\uD83D\uDD04 Memory Reduction: ".concat(stats.memoryReduction, "% (").concat(stats.compressionRatio, "x smaller)"));
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
geometry: indexedGeometry,
|
|
163
|
+
geometryData: geometryData,
|
|
164
|
+
stats: stats,
|
|
165
|
+
materials: materials[0] || new THREE.MeshStandardMaterial({
|
|
166
|
+
color: 0x888888
|
|
167
|
+
})
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Compute simple planar UVs for geometry
|
|
173
|
+
* @param {THREE.BufferGeometry} geometry - The geometry to compute UVs for
|
|
174
|
+
*/
|
|
175
|
+
}, {
|
|
176
|
+
key: "computeSimpleUVs",
|
|
177
|
+
value: function computeSimpleUVs(geometry) {
|
|
178
|
+
var positions = geometry.attributes.position;
|
|
179
|
+
var uvs = new Float32Array(positions.count * 2);
|
|
180
|
+
|
|
181
|
+
// Simple planar projection on XZ plane
|
|
182
|
+
for (var i = 0; i < positions.count; i++) {
|
|
183
|
+
var x = positions.getX(i);
|
|
184
|
+
var z = positions.getZ(i);
|
|
185
|
+
|
|
186
|
+
// Normalize to 0-1 range (simple box projection)
|
|
187
|
+
uvs[i * 2] = (x + 1) * 0.5;
|
|
188
|
+
uvs[i * 2 + 1] = (z + 1) * 0.5;
|
|
189
|
+
}
|
|
190
|
+
geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Calculate geometry statistics
|
|
195
|
+
* @param {THREE.BufferGeometry} geometry - The geometry to analyze
|
|
196
|
+
* @param {string} modelKey - The model key for logging
|
|
197
|
+
* @param {THREE.BufferGeometry} originalGeometry - Optional original non-indexed geometry for comparison
|
|
198
|
+
* @returns {Object} Statistics object
|
|
199
|
+
*/
|
|
200
|
+
}, {
|
|
201
|
+
key: "calculateGeometryStats",
|
|
202
|
+
value: function calculateGeometryStats(geometry, modelKey) {
|
|
203
|
+
var originalGeometry = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
204
|
+
var vertexCount = geometry.attributes.position.count;
|
|
205
|
+
var faceCount = geometry.index ? geometry.index.count / 3 : vertexCount / 3;
|
|
206
|
+
|
|
207
|
+
// Calculate indexed geometry memory usage
|
|
208
|
+
var indexedBytes = 0;
|
|
209
|
+
|
|
210
|
+
// Position attribute (3 floats per vertex)
|
|
211
|
+
if (geometry.attributes.position) {
|
|
212
|
+
indexedBytes += geometry.attributes.position.array.byteLength;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Normal attribute (3 floats per vertex)
|
|
216
|
+
if (geometry.attributes.normal) {
|
|
217
|
+
indexedBytes += geometry.attributes.normal.array.byteLength;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// UV attribute (2 floats per vertex)
|
|
221
|
+
if (geometry.attributes.uv) {
|
|
222
|
+
indexedBytes += geometry.attributes.uv.array.byteLength;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Index buffer (if indexed)
|
|
226
|
+
if (geometry.index) {
|
|
227
|
+
indexedBytes += geometry.index.array.byteLength;
|
|
228
|
+
}
|
|
229
|
+
var indexedSizeKB = (indexedBytes / 1024).toFixed(2);
|
|
230
|
+
|
|
231
|
+
// Calculate non-indexed geometry memory usage for comparison
|
|
232
|
+
var nonIndexedBytes = 0;
|
|
233
|
+
var nonIndexedSizeKB = 0;
|
|
234
|
+
var memoryReduction = 0;
|
|
235
|
+
var compressionRatio = 1;
|
|
236
|
+
if (originalGeometry) {
|
|
237
|
+
// Calculate what the memory would be without indexing
|
|
238
|
+
var originalVertexCount = originalGeometry.attributes.position ? originalGeometry.attributes.position.count : vertexCount;
|
|
239
|
+
|
|
240
|
+
// Position: 3 floats per vertex
|
|
241
|
+
nonIndexedBytes += originalVertexCount * 3 * 4; // 4 bytes per float32
|
|
242
|
+
|
|
243
|
+
// Normals: 3 floats per vertex (if present)
|
|
244
|
+
if (originalGeometry.attributes.normal || geometry.attributes.normal) {
|
|
245
|
+
nonIndexedBytes += originalVertexCount * 3 * 4;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// UVs: 2 floats per vertex (if present)
|
|
249
|
+
if (originalGeometry.attributes.uv || geometry.attributes.uv) {
|
|
250
|
+
nonIndexedBytes += originalVertexCount * 2 * 4;
|
|
251
|
+
}
|
|
252
|
+
nonIndexedSizeKB = (nonIndexedBytes / 1024).toFixed(2);
|
|
253
|
+
memoryReduction = ((nonIndexedBytes - indexedBytes) / nonIndexedBytes * 100).toFixed(1);
|
|
254
|
+
compressionRatio = (nonIndexedBytes / indexedBytes).toFixed(2);
|
|
255
|
+
} else if (geometry.index) {
|
|
256
|
+
// Estimate non-indexed size based on face count
|
|
257
|
+
var estimatedNonIndexedVertices = faceCount * 3; // Each face has 3 vertices
|
|
258
|
+
|
|
259
|
+
// Position: 3 floats per vertex
|
|
260
|
+
nonIndexedBytes += estimatedNonIndexedVertices * 3 * 4;
|
|
261
|
+
|
|
262
|
+
// Normals: 3 floats per vertex (if present)
|
|
263
|
+
if (geometry.attributes.normal) {
|
|
264
|
+
nonIndexedBytes += estimatedNonIndexedVertices * 3 * 4;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// UVs: 2 floats per vertex (if present)
|
|
268
|
+
if (geometry.attributes.uv) {
|
|
269
|
+
nonIndexedBytes += estimatedNonIndexedVertices * 2 * 4;
|
|
270
|
+
}
|
|
271
|
+
nonIndexedSizeKB = (nonIndexedBytes / 1024).toFixed(2);
|
|
272
|
+
memoryReduction = ((nonIndexedBytes - indexedBytes) / nonIndexedBytes * 100).toFixed(1);
|
|
273
|
+
compressionRatio = (nonIndexedBytes / indexedBytes).toFixed(2);
|
|
274
|
+
}
|
|
275
|
+
var stats = {
|
|
276
|
+
modelKey: modelKey,
|
|
277
|
+
vertexCount: vertexCount,
|
|
278
|
+
faceCount: faceCount,
|
|
279
|
+
// Indexed geometry stats
|
|
280
|
+
indexedBytes: indexedBytes,
|
|
281
|
+
indexedSizeKB: parseFloat(indexedSizeKB),
|
|
282
|
+
// Non-indexed geometry stats (for comparison)
|
|
283
|
+
nonIndexedBytes: nonIndexedBytes,
|
|
284
|
+
nonIndexedSizeKB: parseFloat(nonIndexedSizeKB),
|
|
285
|
+
// Compression metrics
|
|
286
|
+
memoryReduction: parseFloat(memoryReduction),
|
|
287
|
+
// Percentage reduction
|
|
288
|
+
compressionRatio: parseFloat(compressionRatio),
|
|
289
|
+
// How many times smaller
|
|
290
|
+
// Legacy compatibility
|
|
291
|
+
totalBytes: indexedBytes,
|
|
292
|
+
// Keep for backward compatibility
|
|
293
|
+
sizeKB: parseFloat(indexedSizeKB),
|
|
294
|
+
// Keep for backward compatibility
|
|
295
|
+
// Features
|
|
296
|
+
indexed: !!geometry.index,
|
|
297
|
+
hasNormals: !!geometry.attributes.normal,
|
|
298
|
+
hasUVs: !!geometry.attributes.uv,
|
|
299
|
+
timestamp: Date.now()
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// Cache the size info
|
|
303
|
+
this.geometrySizeCache.set(modelKey, stats);
|
|
304
|
+
return stats;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Serialize geometry for storage
|
|
309
|
+
* @param {THREE.BufferGeometry} geometry - The geometry to serialize
|
|
310
|
+
* @param {string} modelKey - The model key
|
|
311
|
+
* @param {Object} stats - The geometry statistics
|
|
312
|
+
* @returns {Object} Serializable geometry data
|
|
313
|
+
*/
|
|
314
|
+
}, {
|
|
315
|
+
key: "serializeGeometry",
|
|
316
|
+
value: function serializeGeometry(geometry, modelKey, stats) {
|
|
317
|
+
var data = {
|
|
318
|
+
modelKey: modelKey,
|
|
319
|
+
modelType: 'obj',
|
|
320
|
+
stats: stats,
|
|
321
|
+
attributes: {}
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// Serialize position attribute
|
|
325
|
+
if (geometry.attributes.position) {
|
|
326
|
+
data.attributes.position = {
|
|
327
|
+
array: Array.from(geometry.attributes.position.array),
|
|
328
|
+
itemSize: geometry.attributes.position.itemSize,
|
|
329
|
+
normalized: geometry.attributes.position.normalized
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Serialize normal attribute
|
|
334
|
+
if (geometry.attributes.normal) {
|
|
335
|
+
data.attributes.normal = {
|
|
336
|
+
array: Array.from(geometry.attributes.normal.array),
|
|
337
|
+
itemSize: geometry.attributes.normal.itemSize,
|
|
338
|
+
normalized: geometry.attributes.normal.normalized
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Serialize UV attribute
|
|
343
|
+
if (geometry.attributes.uv) {
|
|
344
|
+
data.attributes.uv = {
|
|
345
|
+
array: Array.from(geometry.attributes.uv.array),
|
|
346
|
+
itemSize: geometry.attributes.uv.itemSize,
|
|
347
|
+
normalized: geometry.attributes.uv.normalized
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Serialize index
|
|
352
|
+
if (geometry.index) {
|
|
353
|
+
data.index = {
|
|
354
|
+
array: Array.from(geometry.index.array),
|
|
355
|
+
itemSize: 1
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
return data;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Deserialize geometry data back to BufferGeometry
|
|
363
|
+
* @param {Object} geometryData - The serialized geometry data
|
|
364
|
+
* @returns {THREE.BufferGeometry} The reconstructed geometry
|
|
365
|
+
*/
|
|
366
|
+
}, {
|
|
367
|
+
key: "deserializeGeometry",
|
|
368
|
+
value: function deserializeGeometry(geometryData) {
|
|
369
|
+
var geometry = new THREE.BufferGeometry();
|
|
370
|
+
|
|
371
|
+
// Restore attributes
|
|
372
|
+
Object.keys(geometryData.attributes).forEach(function (attributeName) {
|
|
373
|
+
var attrData = geometryData.attributes[attributeName];
|
|
374
|
+
var array = new Float32Array(attrData.array);
|
|
375
|
+
var attribute = new THREE.BufferAttribute(array, attrData.itemSize, attrData.normalized);
|
|
376
|
+
geometry.setAttribute(attributeName, attribute);
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
// Restore index if present
|
|
380
|
+
if (geometryData.index) {
|
|
381
|
+
var indexArray = new Uint32Array(geometryData.index.array);
|
|
382
|
+
geometry.setIndex(new THREE.BufferAttribute(indexArray, 1));
|
|
383
|
+
}
|
|
384
|
+
return geometry;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Store indexed geometry in IndexedDB
|
|
389
|
+
* @param {Object} geometryData - The serialized geometry data
|
|
390
|
+
* @returns {Promise} Promise that resolves when stored
|
|
391
|
+
*/
|
|
392
|
+
}, {
|
|
393
|
+
key: "storeGeometryInIDB",
|
|
394
|
+
value: (function () {
|
|
395
|
+
var _storeGeometryInIDB = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(geometryData) {
|
|
396
|
+
var _this3 = this;
|
|
397
|
+
var db, _t;
|
|
398
|
+
return _regenerator().w(function (_context2) {
|
|
399
|
+
while (1) switch (_context2.n) {
|
|
400
|
+
case 0:
|
|
401
|
+
if (this.idbSupported) {
|
|
402
|
+
_context2.n = 1;
|
|
403
|
+
break;
|
|
404
|
+
}
|
|
405
|
+
console.warn('โ ๏ธ IndexedDB not supported, skipping storage');
|
|
406
|
+
return _context2.a(2);
|
|
407
|
+
case 1:
|
|
408
|
+
_context2.p = 1;
|
|
409
|
+
_context2.n = 2;
|
|
410
|
+
return this.initializeIDB();
|
|
411
|
+
case 2:
|
|
412
|
+
db = _context2.v;
|
|
413
|
+
return _context2.a(2, new Promise(function (resolve, reject) {
|
|
414
|
+
var transaction = db.transaction([_this3.storeName], 'readwrite');
|
|
415
|
+
var store = transaction.objectStore(_this3.storeName);
|
|
416
|
+
var request = store.put(geometryData);
|
|
417
|
+
request.onsuccess = function () {
|
|
418
|
+
console.log("\uD83D\uDCBE Stored geometry in IndexedDB: ".concat(geometryData.modelKey));
|
|
419
|
+
resolve();
|
|
420
|
+
};
|
|
421
|
+
request.onerror = function () {
|
|
422
|
+
console.error("\u274C Failed to store geometry: ".concat(geometryData.modelKey));
|
|
423
|
+
reject(request.error);
|
|
424
|
+
};
|
|
425
|
+
}));
|
|
426
|
+
case 3:
|
|
427
|
+
_context2.p = 3;
|
|
428
|
+
_t = _context2.v;
|
|
429
|
+
console.error('โ Error storing geometry in IndexedDB:', _t);
|
|
430
|
+
throw _t;
|
|
431
|
+
case 4:
|
|
432
|
+
return _context2.a(2);
|
|
433
|
+
}
|
|
434
|
+
}, _callee2, this, [[1, 3]]);
|
|
435
|
+
}));
|
|
436
|
+
function storeGeometryInIDB(_x) {
|
|
437
|
+
return _storeGeometryInIDB.apply(this, arguments);
|
|
438
|
+
}
|
|
439
|
+
return storeGeometryInIDB;
|
|
440
|
+
}()
|
|
441
|
+
/**
|
|
442
|
+
* Load indexed geometry from IndexedDB
|
|
443
|
+
* @param {string} modelKey - The model key to load
|
|
444
|
+
* @returns {Promise<Object>} Promise that resolves to geometry data
|
|
445
|
+
*/
|
|
446
|
+
)
|
|
447
|
+
}, {
|
|
448
|
+
key: "loadGeometryFromIDB",
|
|
449
|
+
value: (function () {
|
|
450
|
+
var _loadGeometryFromIDB = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(modelKey) {
|
|
451
|
+
var _this4 = this;
|
|
452
|
+
var db, _t2;
|
|
453
|
+
return _regenerator().w(function (_context3) {
|
|
454
|
+
while (1) switch (_context3.n) {
|
|
455
|
+
case 0:
|
|
456
|
+
if (this.idbSupported) {
|
|
457
|
+
_context3.n = 1;
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
console.warn('โ ๏ธ IndexedDB not supported, cannot load');
|
|
461
|
+
return _context3.a(2, null);
|
|
462
|
+
case 1:
|
|
463
|
+
_context3.p = 1;
|
|
464
|
+
_context3.n = 2;
|
|
465
|
+
return this.initializeIDB();
|
|
466
|
+
case 2:
|
|
467
|
+
db = _context3.v;
|
|
468
|
+
return _context3.a(2, new Promise(function (resolve, reject) {
|
|
469
|
+
var transaction = db.transaction([_this4.storeName], 'readonly');
|
|
470
|
+
var store = transaction.objectStore(_this4.storeName);
|
|
471
|
+
var request = store.get(modelKey);
|
|
472
|
+
request.onsuccess = function () {
|
|
473
|
+
if (request.result) {
|
|
474
|
+
console.log("\uD83D\uDCE6 Loaded geometry from IndexedDB: ".concat(modelKey));
|
|
475
|
+
resolve(request.result);
|
|
476
|
+
} else {
|
|
477
|
+
console.log("\uD83D\uDCED No geometry found in IndexedDB: ".concat(modelKey));
|
|
478
|
+
resolve(null);
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
request.onerror = function () {
|
|
482
|
+
console.error("\u274C Failed to load geometry: ".concat(modelKey));
|
|
483
|
+
reject(request.error);
|
|
484
|
+
};
|
|
485
|
+
}));
|
|
486
|
+
case 3:
|
|
487
|
+
_context3.p = 3;
|
|
488
|
+
_t2 = _context3.v;
|
|
489
|
+
console.error('โ Error loading geometry from IndexedDB:', _t2);
|
|
490
|
+
throw _t2;
|
|
491
|
+
case 4:
|
|
492
|
+
return _context3.a(2);
|
|
493
|
+
}
|
|
494
|
+
}, _callee3, this, [[1, 3]]);
|
|
495
|
+
}));
|
|
496
|
+
function loadGeometryFromIDB(_x2) {
|
|
497
|
+
return _loadGeometryFromIDB.apply(this, arguments);
|
|
498
|
+
}
|
|
499
|
+
return loadGeometryFromIDB;
|
|
500
|
+
}()
|
|
501
|
+
/**
|
|
502
|
+
* Create a custom mesh from indexed geometry
|
|
503
|
+
* @param {string} modelKey - The model key
|
|
504
|
+
* @param {THREE.Material} material - Optional material to use
|
|
505
|
+
* @returns {THREE.Mesh|null} The created mesh or null if not found
|
|
506
|
+
*/
|
|
507
|
+
)
|
|
508
|
+
}, {
|
|
509
|
+
key: "createCustomMesh",
|
|
510
|
+
value: function createCustomMesh(modelKey) {
|
|
511
|
+
var material = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
512
|
+
if (this.indexedGeometryCache.has(modelKey)) {
|
|
513
|
+
var cachedData = this.indexedGeometryCache.get(modelKey);
|
|
514
|
+
var geometry = cachedData.geometry.clone();
|
|
515
|
+
var defaultMaterial = new THREE.MeshStandardMaterial({
|
|
516
|
+
color: 0x888888,
|
|
517
|
+
side: THREE.DoubleSide,
|
|
518
|
+
wireframe: false
|
|
519
|
+
});
|
|
520
|
+
var mesh = new THREE.Mesh(geometry, material || defaultMaterial);
|
|
521
|
+
mesh.userData.modelKey = modelKey;
|
|
522
|
+
mesh.userData.stats = cachedData.stats;
|
|
523
|
+
mesh.userData.isCustomGeometry = true;
|
|
524
|
+
console.log("\uD83C\uDFAF Created custom mesh from indexed geometry: ".concat(modelKey));
|
|
525
|
+
return mesh;
|
|
526
|
+
}
|
|
527
|
+
console.warn("\u26A0\uFE0F Indexed geometry not found in cache: ".concat(modelKey));
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Process an OBJ object and store the result
|
|
533
|
+
* @param {THREE.Object3D} objObject - The loaded OBJ object
|
|
534
|
+
* @param {string} modelKey - The model key
|
|
535
|
+
* @param {boolean} storeInIDB - Whether to store in IndexedDB
|
|
536
|
+
* @returns {Promise<Object>} Promise that resolves to the processed result
|
|
537
|
+
*/
|
|
538
|
+
}, {
|
|
539
|
+
key: "processObjObject",
|
|
540
|
+
value: (function () {
|
|
541
|
+
var _processObjObject = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(objObject, modelKey) {
|
|
542
|
+
var storeInIDB,
|
|
543
|
+
result,
|
|
544
|
+
_args4 = arguments,
|
|
545
|
+
_t3;
|
|
546
|
+
return _regenerator().w(function (_context4) {
|
|
547
|
+
while (1) switch (_context4.n) {
|
|
548
|
+
case 0:
|
|
549
|
+
storeInIDB = _args4.length > 2 && _args4[2] !== undefined ? _args4[2] : true;
|
|
550
|
+
_context4.p = 1;
|
|
551
|
+
// Convert to indexed BufferGeometry
|
|
552
|
+
result = this.objToIndexedBufferGeometry(objObject, modelKey);
|
|
553
|
+
if (result) {
|
|
554
|
+
_context4.n = 2;
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
throw new Error("Failed to convert OBJ to indexed geometry: ".concat(modelKey));
|
|
558
|
+
case 2:
|
|
559
|
+
// Cache the result
|
|
560
|
+
this.indexedGeometryCache.set(modelKey, result);
|
|
561
|
+
|
|
562
|
+
// Store in IndexedDB if requested
|
|
563
|
+
if (!(storeInIDB && result.geometryData)) {
|
|
564
|
+
_context4.n = 3;
|
|
565
|
+
break;
|
|
566
|
+
}
|
|
567
|
+
_context4.n = 3;
|
|
568
|
+
return this.storeGeometryInIDB(result.geometryData);
|
|
569
|
+
case 3:
|
|
570
|
+
console.log("\u2705 Successfully processed OBJ: ".concat(modelKey));
|
|
571
|
+
return _context4.a(2, result);
|
|
572
|
+
case 4:
|
|
573
|
+
_context4.p = 4;
|
|
574
|
+
_t3 = _context4.v;
|
|
575
|
+
console.error("\u274C Error processing OBJ: ".concat(modelKey), _t3);
|
|
576
|
+
throw _t3;
|
|
577
|
+
case 5:
|
|
578
|
+
return _context4.a(2);
|
|
579
|
+
}
|
|
580
|
+
}, _callee4, this, [[1, 4]]);
|
|
581
|
+
}));
|
|
582
|
+
function processObjObject(_x3, _x4) {
|
|
583
|
+
return _processObjObject.apply(this, arguments);
|
|
584
|
+
}
|
|
585
|
+
return processObjObject;
|
|
586
|
+
}()
|
|
587
|
+
/**
|
|
588
|
+
* Get all processed geometry statistics
|
|
589
|
+
* @returns {Array} Array of geometry statistics
|
|
590
|
+
*/
|
|
591
|
+
)
|
|
592
|
+
}, {
|
|
593
|
+
key: "getAllGeometryStats",
|
|
594
|
+
value: function getAllGeometryStats() {
|
|
595
|
+
var stats = [];
|
|
596
|
+
this.geometrySizeCache.forEach(function (stat, modelKey) {
|
|
597
|
+
stats.push(stat);
|
|
598
|
+
});
|
|
599
|
+
return stats.sort(function (a, b) {
|
|
600
|
+
return b.sizeKB - a.sizeKB;
|
|
601
|
+
}); // Sort by size descending
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Get total memory usage of cached geometries
|
|
606
|
+
* @returns {Object} Memory usage statistics
|
|
607
|
+
*/
|
|
608
|
+
}, {
|
|
609
|
+
key: "getMemoryUsage",
|
|
610
|
+
value: function getMemoryUsage() {
|
|
611
|
+
var totalIndexedBytes = 0;
|
|
612
|
+
var totalNonIndexedBytes = 0;
|
|
613
|
+
var totalGeometries = 0;
|
|
614
|
+
this.geometrySizeCache.forEach(function (stats) {
|
|
615
|
+
totalIndexedBytes += stats.indexedBytes;
|
|
616
|
+
totalNonIndexedBytes += stats.nonIndexedBytes;
|
|
617
|
+
totalGeometries++;
|
|
618
|
+
});
|
|
619
|
+
var totalMemoryReduction = totalNonIndexedBytes > 0 ? ((totalNonIndexedBytes - totalIndexedBytes) / totalNonIndexedBytes * 100).toFixed(1) : 0;
|
|
620
|
+
var totalCompressionRatio = totalIndexedBytes > 0 ? (totalNonIndexedBytes / totalIndexedBytes).toFixed(2) : 1;
|
|
621
|
+
return {
|
|
622
|
+
totalGeometries: totalGeometries,
|
|
623
|
+
// Indexed geometry stats
|
|
624
|
+
indexedBytes: totalIndexedBytes,
|
|
625
|
+
indexedKB: (totalIndexedBytes / 1024).toFixed(2),
|
|
626
|
+
indexedMB: (totalIndexedBytes / (1024 * 1024)).toFixed(3),
|
|
627
|
+
// Non-indexed geometry stats
|
|
628
|
+
nonIndexedBytes: totalNonIndexedBytes,
|
|
629
|
+
nonIndexedKB: (totalNonIndexedBytes / 1024).toFixed(2),
|
|
630
|
+
nonIndexedMB: (totalNonIndexedBytes / (1024 * 1024)).toFixed(3),
|
|
631
|
+
// Compression stats
|
|
632
|
+
memoryReduction: parseFloat(totalMemoryReduction),
|
|
633
|
+
compressionRatio: parseFloat(totalCompressionRatio),
|
|
634
|
+
// Legacy compatibility
|
|
635
|
+
totalBytes: totalIndexedBytes,
|
|
636
|
+
totalKB: (totalIndexedBytes / 1024).toFixed(2),
|
|
637
|
+
totalMB: (totalIndexedBytes / (1024 * 1024)).toFixed(2)
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* Clear all caches
|
|
643
|
+
*/
|
|
644
|
+
}, {
|
|
645
|
+
key: "clearCaches",
|
|
646
|
+
value: function clearCaches() {
|
|
647
|
+
console.log('๐งน Clearing OBJ processor caches...');
|
|
648
|
+
|
|
649
|
+
// Dispose of cached geometries
|
|
650
|
+
this.indexedGeometryCache.forEach(function (data, modelKey) {
|
|
651
|
+
if (data.geometry) {
|
|
652
|
+
data.geometry.dispose();
|
|
653
|
+
}
|
|
654
|
+
console.log("\uD83D\uDDD1\uFE0F Disposed cached geometry: ".concat(modelKey));
|
|
655
|
+
});
|
|
656
|
+
this.indexedGeometryCache.clear();
|
|
657
|
+
this.geometrySizeCache.clear();
|
|
658
|
+
console.log('โ
OBJ processor caches cleared');
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Get processing status
|
|
663
|
+
* @returns {Object} Status information
|
|
664
|
+
*/
|
|
665
|
+
}, {
|
|
666
|
+
key: "getStatus",
|
|
667
|
+
value: function getStatus() {
|
|
668
|
+
return {
|
|
669
|
+
cachedGeometries: Array.from(this.indexedGeometryCache.keys()),
|
|
670
|
+
totalCached: this.indexedGeometryCache.size,
|
|
671
|
+
idbSupported: this.idbSupported,
|
|
672
|
+
memoryUsage: this.getMemoryUsage()
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
}]);
|
|
676
|
+
}(); // Export the class
|
|
677
|
+
|
|
678
|
+
export { ObjProcessor, ObjProcessor as default };
|