@littlecarlito/blorktools 0.50.4 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +69 -0
- package/package.json +13 -7
- package/src/asset_debugger/axis-indicator/axis-indicator.css +6 -0
- package/src/asset_debugger/axis-indicator/axis-indicator.html +20 -0
- package/src/asset_debugger/axis-indicator/axis-indicator.js +822 -0
- package/src/asset_debugger/debugger-scene/debugger-scene.css +142 -0
- package/src/asset_debugger/debugger-scene/debugger-scene.html +80 -0
- package/src/asset_debugger/debugger-scene/debugger-scene.js +791 -0
- package/src/asset_debugger/header/header.css +73 -0
- package/src/asset_debugger/header/header.html +24 -0
- package/src/asset_debugger/header/header.js +224 -0
- package/src/asset_debugger/index.html +76 -0
- package/src/asset_debugger/landing-page/landing-page.css +396 -0
- package/src/asset_debugger/landing-page/landing-page.html +81 -0
- package/src/asset_debugger/landing-page/landing-page.js +611 -0
- package/src/asset_debugger/loading-splash/loading-splash.css +195 -0
- package/src/asset_debugger/loading-splash/loading-splash.html +22 -0
- package/src/asset_debugger/loading-splash/loading-splash.js +59 -0
- package/src/asset_debugger/loading-splash/preview-loading-splash.js +66 -0
- package/src/asset_debugger/main.css +14 -0
- package/src/asset_debugger/modals/examples-modal/examples-modal.css +41 -0
- package/src/asset_debugger/modals/examples-modal/examples-modal.html +18 -0
- package/src/asset_debugger/modals/examples-modal/examples-modal.js +111 -0
- package/src/asset_debugger/modals/examples-modal/examples.js +125 -0
- package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.css +452 -0
- package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.html +87 -0
- package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.js +675 -0
- package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.css +219 -0
- package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.html +20 -0
- package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.js +548 -0
- package/src/asset_debugger/modals/settings-modal/settings-modal.css +103 -0
- package/src/asset_debugger/modals/settings-modal/settings-modal.html +158 -0
- package/src/asset_debugger/modals/settings-modal/settings-modal.js +475 -0
- package/src/asset_debugger/panels/asset-panel/asset-panel.css +263 -0
- package/src/asset_debugger/panels/asset-panel/asset-panel.html +123 -0
- package/src/asset_debugger/panels/asset-panel/asset-panel.js +136 -0
- package/src/asset_debugger/panels/asset-panel/atlas-heading/atlas-heading.css +94 -0
- package/src/asset_debugger/panels/asset-panel/atlas-heading/atlas-heading.js +312 -0
- package/src/asset_debugger/panels/asset-panel/mesh-heading/mesh-heading.css +129 -0
- package/src/asset_debugger/panels/asset-panel/mesh-heading/mesh-heading.js +486 -0
- package/src/asset_debugger/panels/asset-panel/rig-heading/rig-heading.css +545 -0
- package/src/asset_debugger/panels/asset-panel/rig-heading/rig-heading.js +538 -0
- package/src/asset_debugger/panels/asset-panel/uv-heading/uv-heading.css +70 -0
- package/src/asset_debugger/panels/asset-panel/uv-heading/uv-heading.js +586 -0
- package/src/asset_debugger/panels/world-panel/world-panel.css +364 -0
- package/src/asset_debugger/panels/world-panel/world-panel.html +173 -0
- package/src/asset_debugger/panels/world-panel/world-panel.js +1891 -0
- package/src/asset_debugger/router.js +190 -0
- package/src/asset_debugger/util/animation/playback/animation-playback-controller.js +150 -0
- package/src/asset_debugger/util/animation/playback/animation-preview-controller.js +316 -0
- package/src/asset_debugger/util/animation/playback/css3d-bounce-controller.js +400 -0
- package/src/asset_debugger/util/animation/playback/css3d-reversal-controller.js +821 -0
- package/src/asset_debugger/util/animation/render/css3d-prerender-controller.js +696 -0
- package/src/asset_debugger/util/animation/render/debug-texture-factory.js +0 -0
- package/src/asset_debugger/util/animation/render/iframe2texture-render-controller.js +199 -0
- package/src/asset_debugger/util/animation/render/image2texture-prerender-controller.js +461 -0
- package/src/asset_debugger/util/animation/render/pbr-material-factory.js +82 -0
- package/src/asset_debugger/util/common.css +280 -0
- package/src/asset_debugger/util/data/animation-classifier.js +323 -0
- package/src/asset_debugger/util/data/duplicate-handler.js +20 -0
- package/src/asset_debugger/util/data/glb-buffer-manager.js +407 -0
- package/src/asset_debugger/util/data/glb-classifier.js +290 -0
- package/src/asset_debugger/util/data/html-formatter.js +76 -0
- package/src/asset_debugger/util/data/html-linter.js +276 -0
- package/src/asset_debugger/util/data/localstorage-manager.js +265 -0
- package/src/asset_debugger/util/data/mesh-html-manager.js +295 -0
- package/src/asset_debugger/util/data/string-serder.js +303 -0
- package/src/asset_debugger/util/data/texture-classifier.js +663 -0
- package/src/asset_debugger/util/data/upload/background-file-handler.js +292 -0
- package/src/asset_debugger/util/data/upload/dropzone-preview-controller.js +396 -0
- package/src/asset_debugger/util/data/upload/file-upload-manager.js +495 -0
- package/src/asset_debugger/util/data/upload/glb-file-handler.js +36 -0
- package/src/asset_debugger/util/data/upload/glb-preview-controller.js +317 -0
- package/src/asset_debugger/util/data/upload/lighting-file-handler.js +194 -0
- package/src/asset_debugger/util/data/upload/model-file-manager.js +104 -0
- package/src/asset_debugger/util/data/upload/texture-file-handler.js +166 -0
- package/src/asset_debugger/util/data/upload/zip-handler.js +686 -0
- package/src/asset_debugger/util/loaders/html2canvas-loader.js +107 -0
- package/src/asset_debugger/util/rig/bone-kinematics.js +403 -0
- package/src/asset_debugger/util/rig/rig-constraint-manager.js +618 -0
- package/src/asset_debugger/util/rig/rig-controller.js +612 -0
- package/src/asset_debugger/util/rig/rig-factory.js +628 -0
- package/src/asset_debugger/util/rig/rig-handle-factory.js +46 -0
- package/src/asset_debugger/util/rig/rig-label-factory.js +441 -0
- package/src/asset_debugger/util/rig/rig-mouse-handler.js +377 -0
- package/src/asset_debugger/util/rig/rig-state-manager.js +175 -0
- package/src/asset_debugger/util/rig/rig-tooltip-manager.js +267 -0
- package/src/asset_debugger/util/rig/rig-ui-factory.js +700 -0
- package/src/asset_debugger/util/scene/background-manager.js +284 -0
- package/src/asset_debugger/util/scene/camera-controller.js +243 -0
- package/src/asset_debugger/util/scene/css3d-debug-controller.js +406 -0
- package/src/asset_debugger/util/scene/css3d-frame-factory.js +113 -0
- package/src/asset_debugger/util/scene/css3d-scene-manager.js +529 -0
- package/src/asset_debugger/util/scene/glb-controller.js +208 -0
- package/src/asset_debugger/util/scene/lighting-manager.js +690 -0
- package/src/asset_debugger/util/scene/threejs-model-manager.js +437 -0
- package/src/asset_debugger/util/scene/threejs-preview-manager.js +207 -0
- package/src/asset_debugger/util/scene/threejs-preview-setup.js +478 -0
- package/src/asset_debugger/util/scene/threejs-scene-controller.js +286 -0
- package/src/asset_debugger/util/scene/ui-manager.js +107 -0
- package/src/asset_debugger/util/state/animation-state.js +128 -0
- package/src/asset_debugger/util/state/css3d-state.js +83 -0
- package/src/asset_debugger/util/state/glb-preview-state.js +31 -0
- package/src/asset_debugger/util/state/log-util.js +197 -0
- package/src/asset_debugger/util/state/scene-state.js +452 -0
- package/src/asset_debugger/util/state/threejs-state.js +54 -0
- package/src/asset_debugger/util/workers/lighting-worker.js +61 -0
- package/src/asset_debugger/util/workers/model-worker.js +109 -0
- package/src/asset_debugger/util/workers/texture-worker.js +54 -0
- package/src/asset_debugger/util/workers/worker-manager.js +212 -0
- package/src/asset_debugger/widgets/mesh-info-widget.js +280 -0
- package/src/index.html +261 -0
- package/src/index.js +8 -0
- package/vite.config.js +66 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create or get an error log container
|
|
3
|
+
* @param {HTMLElement} container - Parent container for the error log
|
|
4
|
+
* @param {string} [logId] - Custom ID for the error log element
|
|
5
|
+
* @param {string} [className] - Custom class name for styling
|
|
6
|
+
* @returns {HTMLElement} The error log element
|
|
7
|
+
*/
|
|
8
|
+
export function createErrorLog(container, logId = 'error-log', className = 'error-log') {
|
|
9
|
+
if (!container) throw new Error('Container element is required');
|
|
10
|
+
|
|
11
|
+
let errorLog = container.querySelector(`#${logId}`);
|
|
12
|
+
|
|
13
|
+
if (!errorLog) {
|
|
14
|
+
errorLog = document.createElement('div');
|
|
15
|
+
errorLog.id = logId;
|
|
16
|
+
errorLog.className = className;
|
|
17
|
+
errorLog.style.display = 'none';
|
|
18
|
+
container.appendChild(errorLog);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return errorLog;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Add an error entry to an error log
|
|
26
|
+
* @param {HTMLElement} errorLog - The error log container
|
|
27
|
+
* @param {string} message - Error message to display
|
|
28
|
+
* @param {Object} [options] - Additional options
|
|
29
|
+
* @param {boolean} [options.showTimestamp=true] - Whether to show timestamp
|
|
30
|
+
* @param {string} [options.entryClassName='error-entry'] - Class name for the entry
|
|
31
|
+
* @param {string} [options.timeClassName='error-time'] - Class name for the timestamp
|
|
32
|
+
*/
|
|
33
|
+
export function addErrorEntry(errorLog, message, options = {}) {
|
|
34
|
+
const {
|
|
35
|
+
showTimestamp = true,
|
|
36
|
+
entryClassName = 'error-entry',
|
|
37
|
+
timeClassName = 'error-time'
|
|
38
|
+
} = options;
|
|
39
|
+
|
|
40
|
+
if (!errorLog) throw new Error('Error log element is required');
|
|
41
|
+
|
|
42
|
+
const errorEntry = document.createElement('div');
|
|
43
|
+
errorEntry.className = entryClassName;
|
|
44
|
+
errorEntry.textContent = message;
|
|
45
|
+
|
|
46
|
+
if (showTimestamp) {
|
|
47
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
48
|
+
const timeSpan = document.createElement('span');
|
|
49
|
+
timeSpan.className = timeClassName;
|
|
50
|
+
timeSpan.textContent = `[${timestamp}] `;
|
|
51
|
+
errorEntry.prepend(timeSpan);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
errorLog.appendChild(errorEntry);
|
|
55
|
+
errorLog.style.display = 'block';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Log an error to a container with automatic error log creation
|
|
60
|
+
* @param {string} message - Error message to display
|
|
61
|
+
* @param {HTMLElement} container - Container for the error log
|
|
62
|
+
* @param {Object} [options] - Configuration options
|
|
63
|
+
* @param {string} [options.logId] - Custom ID for error log
|
|
64
|
+
* @param {string} [options.logClassName] - Custom class for error log
|
|
65
|
+
* @param {Function} [options.statusCallback] - Function to call for status updates
|
|
66
|
+
* @param {boolean} [options.consoleLog=true] - Whether to also log to console
|
|
67
|
+
* @param {Object} [options.entryOptions] - Options passed to addErrorEntry
|
|
68
|
+
*/
|
|
69
|
+
export function logError(message, container, options = {}) {
|
|
70
|
+
const {
|
|
71
|
+
logId = 'error-log',
|
|
72
|
+
logClassName = 'error-log',
|
|
73
|
+
statusCallback,
|
|
74
|
+
consoleLog = true,
|
|
75
|
+
entryOptions = {}
|
|
76
|
+
} = options;
|
|
77
|
+
|
|
78
|
+
if (!container) throw new Error('Container element is required');
|
|
79
|
+
|
|
80
|
+
const errorLog = createErrorLog(container, logId, logClassName);
|
|
81
|
+
addErrorEntry(errorLog, message, entryOptions);
|
|
82
|
+
|
|
83
|
+
if (statusCallback && typeof statusCallback === 'function') {
|
|
84
|
+
statusCallback(message, 'error');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (consoleLog) {
|
|
88
|
+
console.error(message);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Clear all entries from an error log
|
|
94
|
+
* @param {HTMLElement} errorLog - The error log to clear
|
|
95
|
+
* @param {boolean} [hide=true] - Whether to hide the log after clearing
|
|
96
|
+
*/
|
|
97
|
+
export function clearErrorLog(errorLog, hide = true) {
|
|
98
|
+
if (!errorLog) return;
|
|
99
|
+
|
|
100
|
+
errorLog.innerHTML = '';
|
|
101
|
+
if (hide) {
|
|
102
|
+
errorLog.style.display = 'none';
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Get all error entries from an error log
|
|
108
|
+
* @param {HTMLElement} errorLog - The error log to read from
|
|
109
|
+
* @returns {string[]} Array of error messages
|
|
110
|
+
*/
|
|
111
|
+
export function getErrorEntries(errorLog) {
|
|
112
|
+
if (!errorLog) return [];
|
|
113
|
+
|
|
114
|
+
const entries = errorLog.querySelectorAll('.error-entry');
|
|
115
|
+
return Array.from(entries).map(entry => entry.textContent);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Utility function to get caller information from stack trace
|
|
120
|
+
* @param {number} [skipLevels=1] - Number of stack levels to skip (default skips the getCaller function itself)
|
|
121
|
+
* @returns {string} Caller information in format "function@file.js:line"
|
|
122
|
+
*/
|
|
123
|
+
export function getCaller(skipLevels = 1) {
|
|
124
|
+
try {
|
|
125
|
+
const stack = new Error().stack;
|
|
126
|
+
const lines = stack.split('\n');
|
|
127
|
+
|
|
128
|
+
// Skip this function and any additional levels requested
|
|
129
|
+
const callerLine = lines[skipLevels + 1];
|
|
130
|
+
if (!callerLine) return 'no-stack';
|
|
131
|
+
|
|
132
|
+
// Quick extraction - prioritize speed over perfection
|
|
133
|
+
// Look for common patterns: "at function (file:line)" or "function@file:line"
|
|
134
|
+
if (callerLine.includes('at ')) {
|
|
135
|
+
const atMatch = callerLine.match(/at\s+([^(]+?)(?:\s+\(.*?([^\/\\]+):(\d+)|.*?([^\/\\]+):(\d+))/);
|
|
136
|
+
if (atMatch) {
|
|
137
|
+
const func = atMatch[1]?.trim() || 'anonymous';
|
|
138
|
+
const file = atMatch[2] || atMatch[4];
|
|
139
|
+
const line = atMatch[3] || atMatch[5];
|
|
140
|
+
return file && line ? `${func}@${file}:${line}` : func;
|
|
141
|
+
}
|
|
142
|
+
} else if (callerLine.includes('@')) {
|
|
143
|
+
const atMatch = callerLine.match(/([^@]+)@.*?([^\/\\]+):(\d+)/);
|
|
144
|
+
if (atMatch) return `${atMatch[1]}@${atMatch[2]}:${atMatch[3]}`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Fallback: just show a truncated version of the line
|
|
148
|
+
return callerLine.substring(callerLine.lastIndexOf('/') + 1, callerLine.length).trim() || 'unknown';
|
|
149
|
+
} catch (e) {
|
|
150
|
+
return 'error';
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Debug reporting function for animation analysis
|
|
155
|
+
export function logAnimationAnalysisReport(renderType, data) {
|
|
156
|
+
const {
|
|
157
|
+
frameCount,
|
|
158
|
+
duration,
|
|
159
|
+
isFinite,
|
|
160
|
+
loopDetected,
|
|
161
|
+
endDetected,
|
|
162
|
+
analysisTime,
|
|
163
|
+
metrics
|
|
164
|
+
} = data;
|
|
165
|
+
|
|
166
|
+
console.debug(
|
|
167
|
+
`%c Animation Analysis Report: ${renderType} %c`,
|
|
168
|
+
'background: #4285f4; color: white; padding: 2px 6px; border-radius: 2px; font-weight: bold;',
|
|
169
|
+
'background: transparent;'
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
console.debug({
|
|
173
|
+
renderType,
|
|
174
|
+
framesAnalyzed: frameCount,
|
|
175
|
+
duration: duration ? `${(duration/1000).toFixed(2)}s` : 'unknown',
|
|
176
|
+
isFiniteAnimation: isFinite,
|
|
177
|
+
loopDetected,
|
|
178
|
+
endDetected,
|
|
179
|
+
analysisTime: `${(analysisTime/1000).toFixed(2)}s`,
|
|
180
|
+
metrics
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Log errors specifically for preview context using generic logging
|
|
186
|
+
*/
|
|
187
|
+
export function logPreviewError(message, previewContent, existingErrorLog, statusCallback) {
|
|
188
|
+
logError(message, previewContent, {
|
|
189
|
+
logId: 'html-preview-error-log',
|
|
190
|
+
logClassName: 'preview-error-log',
|
|
191
|
+
statusCallback: statusCallback || showStatus,
|
|
192
|
+
entryOptions: {
|
|
193
|
+
entryClassName: 'error-entry',
|
|
194
|
+
timeClassName: 'error-time'
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Texture Debugger - State Management Module
|
|
3
|
+
*
|
|
4
|
+
* This module manages the global state for the texture debugger tool.
|
|
5
|
+
* It provides methods to initialize, access, and update the application state.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { saveCurrentSession, loadCurrentSession, clearSessionData } from '../data/localstorage-manager.js';
|
|
9
|
+
import { getCaller } from './log-util.js';
|
|
10
|
+
|
|
11
|
+
// Define the initial state
|
|
12
|
+
const initialState = {
|
|
13
|
+
sessionId: null,
|
|
14
|
+
timestamp: null,
|
|
15
|
+
scene: null,
|
|
16
|
+
camera: null,
|
|
17
|
+
renderer: null,
|
|
18
|
+
controls: null,
|
|
19
|
+
|
|
20
|
+
textureFiles: {
|
|
21
|
+
baseColor: null, // File object
|
|
22
|
+
orm: null, // File object
|
|
23
|
+
normal: null // File object
|
|
24
|
+
},
|
|
25
|
+
// Texture objects (THREE.Texture objects)
|
|
26
|
+
textureObjects: {
|
|
27
|
+
baseColor: null,
|
|
28
|
+
orm: null,
|
|
29
|
+
normal: null
|
|
30
|
+
},
|
|
31
|
+
modelFile: null, // File object
|
|
32
|
+
model: null,
|
|
33
|
+
cube: null,
|
|
34
|
+
lightingFile: null, // File object
|
|
35
|
+
backgroundFile: null, // File object
|
|
36
|
+
backgroundTexture: null,
|
|
37
|
+
|
|
38
|
+
// Animation ID for cancelAnimationFrame
|
|
39
|
+
animationId: null,
|
|
40
|
+
|
|
41
|
+
// Mesh management
|
|
42
|
+
meshes: [],
|
|
43
|
+
meshGroups: {},
|
|
44
|
+
|
|
45
|
+
// Atlas visualization
|
|
46
|
+
currentTextureType: 'baseColor',
|
|
47
|
+
currentUvRegion: { min: [0, 0], max: [1, 1] },
|
|
48
|
+
|
|
49
|
+
// UV data
|
|
50
|
+
availableUvSets: [],
|
|
51
|
+
uvSetNames: [],
|
|
52
|
+
currentUvSet: 0,
|
|
53
|
+
screenMeshes: [], // New: display/screen meshes
|
|
54
|
+
uvMappingInfo: {}, // New: detailed mapping info for UV channels
|
|
55
|
+
|
|
56
|
+
// Status flags
|
|
57
|
+
isDebugStarted: false,
|
|
58
|
+
useCustomModel: false,
|
|
59
|
+
useLightingTestCube: false, // Flag to indicate we should use the special lighting test cube
|
|
60
|
+
|
|
61
|
+
// Helper functions
|
|
62
|
+
cycleAtlasSegments: null, // New: function to cycle atlas segments
|
|
63
|
+
setCurrentUvRegion: null, // New: function to set current UV region
|
|
64
|
+
switchUvChannel: null, // New: function to switch UV channel
|
|
65
|
+
|
|
66
|
+
// Environment lighting
|
|
67
|
+
environmentLightingEnabled: false,
|
|
68
|
+
ambientLight: null,
|
|
69
|
+
directionalLight: null,
|
|
70
|
+
|
|
71
|
+
// Material properties
|
|
72
|
+
materialProperties: {
|
|
73
|
+
metalness: 0.5,
|
|
74
|
+
roughness: 0.5,
|
|
75
|
+
normalScale: 1.0
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
// UV unwrapping options
|
|
79
|
+
unwrapOptions: {
|
|
80
|
+
wireframe: true,
|
|
81
|
+
displayUVs: true,
|
|
82
|
+
textureDisplay: 'baseColor'
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
// Rig related properties
|
|
86
|
+
rigOptions: {
|
|
87
|
+
autoRotate: false,
|
|
88
|
+
showSkeleton: true,
|
|
89
|
+
enableIK: true,
|
|
90
|
+
currentAnimation: null,
|
|
91
|
+
playAnimation: false,
|
|
92
|
+
animationSpeed: 1.0
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// The actual state object - singleton
|
|
97
|
+
let state = null;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Initialize a new draft state for the landing page
|
|
101
|
+
* This state won't be saved as current until startDebugging is called
|
|
102
|
+
* @returns {Object} The initialized state object
|
|
103
|
+
*/
|
|
104
|
+
export function initDraftState() {
|
|
105
|
+
// Generate a new session ID and timestamp
|
|
106
|
+
const sessionId = Date.now().toString();
|
|
107
|
+
const timestamp = new Date().toISOString();
|
|
108
|
+
|
|
109
|
+
// Create a new state object with session ID and timestamp
|
|
110
|
+
state = { ...initialState, sessionId, timestamp };
|
|
111
|
+
|
|
112
|
+
return state;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Start a new debugging session with the current draft state
|
|
117
|
+
* This makes the current draft state the "current" session
|
|
118
|
+
* @returns {Object} The current state object
|
|
119
|
+
*/
|
|
120
|
+
export function startDebugging() {
|
|
121
|
+
if (!state) {
|
|
122
|
+
state = initDraftState();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Save to localStorage as current session
|
|
126
|
+
saveCurrentSession(state);
|
|
127
|
+
|
|
128
|
+
return state;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Update a specific part of the state
|
|
133
|
+
* @param {string} key - The key to update
|
|
134
|
+
* @param {any} value - The new value
|
|
135
|
+
* @returns {Object} The updated state
|
|
136
|
+
*/
|
|
137
|
+
export function updateState(key, value) {
|
|
138
|
+
if (!state) {
|
|
139
|
+
initDraftState();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Helper function to get file name or null
|
|
143
|
+
const getFileName = (file) => file ? file.name : null;
|
|
144
|
+
|
|
145
|
+
// Log the state update with caller information (throttled to avoid spam)
|
|
146
|
+
const now = Date.now();
|
|
147
|
+
if (!updateState._lastLog || now - updateState._lastLog > 100) { // Only log every 100ms
|
|
148
|
+
updateState._lastLog = now;
|
|
149
|
+
console.debug('State update:', {
|
|
150
|
+
caller: getCaller(1), // Skip 1 level (the updateState function itself)
|
|
151
|
+
key: typeof key === 'object' ? Object.keys(key) : key,
|
|
152
|
+
model: getFileName(state.modelFile),
|
|
153
|
+
lighting: getFileName(state.lightingFile),
|
|
154
|
+
background: getFileName(state.backgroundFile),
|
|
155
|
+
textures: {
|
|
156
|
+
baseColor: getFileName(state.textureFiles?.baseColor),
|
|
157
|
+
orm: getFileName(state.textureFiles?.orm),
|
|
158
|
+
normal: getFileName(state.textureFiles?.normal)
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (typeof key === 'object') {
|
|
164
|
+
Object.assign(state, key);
|
|
165
|
+
} else {
|
|
166
|
+
state[key] = value;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return state;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Get the current application state
|
|
174
|
+
* @returns {Object} The current state object
|
|
175
|
+
*/
|
|
176
|
+
export function getState() {
|
|
177
|
+
if (!state) {
|
|
178
|
+
// Try to load from localStorage
|
|
179
|
+
const savedState = loadCurrentSession();
|
|
180
|
+
if (savedState) {
|
|
181
|
+
console.debug('Loading state from localStorage:', {
|
|
182
|
+
hasModelFile: !!savedState.modelFile,
|
|
183
|
+
hasLightingFile: !!savedState.lightingFile,
|
|
184
|
+
hasBackgroundFile: !!savedState.backgroundFile,
|
|
185
|
+
hasTextureFiles: savedState.textureFiles ? Object.values(savedState.textureFiles).some(f => f !== null) : false,
|
|
186
|
+
sessionId: savedState.sessionId,
|
|
187
|
+
timestamp: savedState.timestamp
|
|
188
|
+
});
|
|
189
|
+
state = savedState;
|
|
190
|
+
} else {
|
|
191
|
+
console.debug('No saved state found in localStorage, initializing new state');
|
|
192
|
+
state = initDraftState();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return state;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Reset the state to initial values
|
|
200
|
+
* @returns {Object} The reset state
|
|
201
|
+
*/
|
|
202
|
+
export function resetState() {
|
|
203
|
+
state = initDraftState();
|
|
204
|
+
return state;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Clear all session data
|
|
209
|
+
*/
|
|
210
|
+
export function clearState() {
|
|
211
|
+
clearSessionData();
|
|
212
|
+
state = null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function hasFiles() {
|
|
216
|
+
return hasModelFile() || hasLightingFile() || hasBackgroundFile()
|
|
217
|
+
|| hasBaseColorFile() || hasOrmFile() || hasNormalFile();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export function hasModelFile() {
|
|
221
|
+
return state.modelFile !== null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function getModelFile() {
|
|
225
|
+
return state.modelFile;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function hasLightingFile() {
|
|
229
|
+
return state.lightingFile !== null;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export function getLightingFile() {
|
|
233
|
+
return state.lightingFile;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function hasBackgroundFile() {
|
|
237
|
+
return state.backgroundFile !== null;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function getBackgroundFile() {
|
|
241
|
+
return state.backgroundFile;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function hasBaseColorFile() {
|
|
245
|
+
return state.textureFiles.baseColor !== null;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export function getBaseColorFile() {
|
|
249
|
+
return state.textureFiles.baseColor;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export function hasOrmFile() {
|
|
253
|
+
return state.textureFiles.orm !== null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function getOrmFile() {
|
|
257
|
+
return state.textureFiles.orm;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export function hasNormalFile() {
|
|
261
|
+
return state.textureFiles.normal !== null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function getNormalFile() {
|
|
265
|
+
return state.textureFiles.normal;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Update multiple parts of the state at once
|
|
270
|
+
* @param {Object} updates - An object with keys and values to update
|
|
271
|
+
* @returns {Object} The updated state
|
|
272
|
+
*/
|
|
273
|
+
export function setState(updates) {
|
|
274
|
+
if (!state) {
|
|
275
|
+
initDraftState();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
Object.assign(state, updates);
|
|
279
|
+
|
|
280
|
+
return state;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Prints a formatted table report of the current state's file status
|
|
285
|
+
* @param {string} [caller='unknown'] - The name of the calling function/module
|
|
286
|
+
* @returns {void}
|
|
287
|
+
*/
|
|
288
|
+
export function printStateReport(caller = 'unknown') {
|
|
289
|
+
console.log('\nState Report (called by ' + caller + ')\n');
|
|
290
|
+
|
|
291
|
+
const files = [
|
|
292
|
+
{ name: 'Model', file: getModelFile(), hasFile: hasModelFile() },
|
|
293
|
+
{ name: 'Lighting', file: getLightingFile(), hasFile: hasLightingFile() },
|
|
294
|
+
{ name: 'Background', file: getBackgroundFile(), hasFile: hasBackgroundFile() },
|
|
295
|
+
{ name: 'Base Color', file: getBaseColorFile(), hasFile: hasBaseColorFile() },
|
|
296
|
+
{ name: 'ORM', file: getOrmFile(), hasFile: hasOrmFile() },
|
|
297
|
+
{ name: 'Normal', file: getNormalFile(), hasFile: hasNormalFile() }
|
|
298
|
+
];
|
|
299
|
+
|
|
300
|
+
console.table(
|
|
301
|
+
files.map(({ name, file, hasFile }) => ({
|
|
302
|
+
'Drop Box': name,
|
|
303
|
+
'File Name': file?.name || 'None',
|
|
304
|
+
'Processed': hasFile
|
|
305
|
+
}))
|
|
306
|
+
);
|
|
307
|
+
console.log('\n');
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* NEW: Clear all file-related state
|
|
312
|
+
* This should be called when navigating between pages to prevent state pollution
|
|
313
|
+
* @param {boolean} skipLocalStorage - Whether to skip saving to localStorage (optional)
|
|
314
|
+
*/
|
|
315
|
+
export function clearAllFiles(skipLocalStorage = false) {
|
|
316
|
+
console.log('Clearing all file state for clean navigation...');
|
|
317
|
+
|
|
318
|
+
if (!state) {
|
|
319
|
+
console.log('No state to clear');
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Clear all file references
|
|
324
|
+
state.modelFile = null;
|
|
325
|
+
state.lightingFile = null;
|
|
326
|
+
state.backgroundFile = null;
|
|
327
|
+
state.backgroundTexture = null;
|
|
328
|
+
state.environmentTexture = null;
|
|
329
|
+
|
|
330
|
+
// Clear texture files
|
|
331
|
+
state.textureFiles = {
|
|
332
|
+
baseColor: null,
|
|
333
|
+
orm: null,
|
|
334
|
+
normal: null
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
// Clear texture objects
|
|
338
|
+
state.textureObjects = {
|
|
339
|
+
baseColor: null,
|
|
340
|
+
orm: null,
|
|
341
|
+
normal: null
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
// Don't clear scene, camera, renderer, controls as those are handled by ThreeJS cleanup
|
|
345
|
+
// Don't clear meshes as those are part of the scene cleanup
|
|
346
|
+
|
|
347
|
+
console.log('File state cleared successfully');
|
|
348
|
+
|
|
349
|
+
// Skip localStorage operations if requested
|
|
350
|
+
if (skipLocalStorage) {
|
|
351
|
+
console.log('Skipping localStorage operations as requested for faster navigation');
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// FIXED: Use safe save function that handles quota exceeded
|
|
356
|
+
import('../data/localstorage-manager.js').then(localStorageModule => {
|
|
357
|
+
if (localStorageModule.safeSaveCurrentSession) {
|
|
358
|
+
const success = localStorageModule.safeSaveCurrentSession(state);
|
|
359
|
+
if (!success) {
|
|
360
|
+
console.warn('Could not save cleared state to localStorage, continuing without persistence');
|
|
361
|
+
}
|
|
362
|
+
} else {
|
|
363
|
+
// Fallback to regular save
|
|
364
|
+
try {
|
|
365
|
+
saveCurrentSession(state);
|
|
366
|
+
} catch (error) {
|
|
367
|
+
console.warn('Could not save session:', error.message);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}).catch(error => {
|
|
371
|
+
console.warn('Could not import localStorage utility:', error);
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* NEW: Clear only lighting-related state
|
|
377
|
+
*/
|
|
378
|
+
export function clearLightingState() {
|
|
379
|
+
if (!state) return;
|
|
380
|
+
|
|
381
|
+
console.log('Clearing lighting state...');
|
|
382
|
+
state.lightingFile = null;
|
|
383
|
+
state.environmentTexture = null;
|
|
384
|
+
state.environmentLightingEnabled = false;
|
|
385
|
+
|
|
386
|
+
// Clear scene environment if it exists
|
|
387
|
+
if (state.scene) {
|
|
388
|
+
state.scene.environment = null;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* NEW: Clear only background-related state
|
|
394
|
+
*/
|
|
395
|
+
export function clearBackgroundState() {
|
|
396
|
+
if (!state) return;
|
|
397
|
+
|
|
398
|
+
console.log('Clearing background state...');
|
|
399
|
+
state.backgroundFile = null;
|
|
400
|
+
state.backgroundTexture = null;
|
|
401
|
+
|
|
402
|
+
// Clear scene background if it exists
|
|
403
|
+
if (state.scene) {
|
|
404
|
+
state.scene.background = null;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* NEW: Clear only texture-related state
|
|
410
|
+
*/
|
|
411
|
+
export function clearTextureState() {
|
|
412
|
+
if (!state) return;
|
|
413
|
+
|
|
414
|
+
console.log('Clearing texture state...');
|
|
415
|
+
state.textureFiles = {
|
|
416
|
+
baseColor: null,
|
|
417
|
+
orm: null,
|
|
418
|
+
normal: null
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
state.textureObjects = {
|
|
422
|
+
baseColor: null,
|
|
423
|
+
orm: null,
|
|
424
|
+
normal: null
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* NEW: Reset to clean navigation state
|
|
430
|
+
* This preserves the session but clears all loaded content
|
|
431
|
+
*/
|
|
432
|
+
export function resetToNavigationState() {
|
|
433
|
+
console.log('Resetting to clean navigation state...');
|
|
434
|
+
|
|
435
|
+
if (!state) {
|
|
436
|
+
state = initDraftState();
|
|
437
|
+
return state;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Preserve session info
|
|
441
|
+
const sessionId = state.sessionId;
|
|
442
|
+
const timestamp = state.timestamp;
|
|
443
|
+
|
|
444
|
+
// Reset to initial state but preserve session
|
|
445
|
+
state = { ...initialState, sessionId, timestamp };
|
|
446
|
+
|
|
447
|
+
// Save the reset state
|
|
448
|
+
saveCurrentSession(state);
|
|
449
|
+
|
|
450
|
+
console.log('Reset to navigation state complete');
|
|
451
|
+
return state;
|
|
452
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export let pendingTextureUpdate = false;
|
|
2
|
+
export let previewPlane;
|
|
3
|
+
export let animationPreviewScene, animationPreviewCamera, animationPreviewRenderer;
|
|
4
|
+
export let animationCss3dScene, animationCss3dRenderer, animationCss3dObject;
|
|
5
|
+
export let frameBuffer = [];
|
|
6
|
+
export let previewRenderTarget = null;
|
|
7
|
+
|
|
8
|
+
export function setAnimationCss3dScene(incomingValue) {
|
|
9
|
+
animationCss3dScene = incomingValue;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function setAnimationCss3dRenderer(incomingValue) {
|
|
13
|
+
animationCss3dRenderer = incomingValue;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function setAnimationCss3dObject(incomingValue) {
|
|
17
|
+
animationCss3dObject = incomingValue;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function setAnimationPreviewScene(incomingValue) {
|
|
21
|
+
animationPreviewScene = incomingValue;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function setAnimationPreviewRenderer(incomingValue) {
|
|
25
|
+
animationPreviewRenderer = incomingValue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function setPreviewPlane(incomingValue) {
|
|
29
|
+
previewPlane = incomingValue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function setPreviewRenderTarget(incomingValue) {
|
|
33
|
+
previewRenderTarget = incomingValue;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function setAnimationPreviewCamera(incomingValue) {
|
|
37
|
+
animationPreviewCamera = incomingValue;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function setPendingTextureUpdate(incomingValue) {
|
|
41
|
+
pendingTextureUpdate = incomingValue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function resetThreeJsState() {
|
|
45
|
+
previewPlane = null;
|
|
46
|
+
animationPreviewScene = null;
|
|
47
|
+
animationPreviewCamera = null;
|
|
48
|
+
animationPreviewRenderer = null;
|
|
49
|
+
animationCss3dScene = null;
|
|
50
|
+
animationCss3dRenderer = null;
|
|
51
|
+
animationCss3dObject = null;
|
|
52
|
+
previewRenderTarget = null;
|
|
53
|
+
frameBuffer = [];
|
|
54
|
+
}
|