@fps-games/editor 0.1.1-beta.9 → 0.1.2-beta.2
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/local-editor-harness.d.ts +52 -4
- package/dist/local-editor-harness.d.ts.map +1 -1
- package/dist/local-editor-harness.js +437 -91
- package/dist/local-editor-harness.js.map +1 -1
- package/dist/local-editor-scene-render-scheduler.d.ts +33 -0
- package/dist/local-editor-scene-render-scheduler.d.ts.map +1 -0
- package/dist/local-editor-scene-render-scheduler.js +160 -0
- package/dist/local-editor-scene-render-scheduler.js.map +1 -0
- package/dist/local-editor-scene-view-interaction-runtime.d.ts +22 -0
- package/dist/local-editor-scene-view-interaction-runtime.d.ts.map +1 -0
- package/dist/local-editor-scene-view-interaction-runtime.js +80 -0
- package/dist/local-editor-scene-view-interaction-runtime.js.map +1 -0
- package/dist/local-editor-viewport-render-coordinator.d.ts +17 -0
- package/dist/local-editor-viewport-render-coordinator.d.ts.map +1 -0
- package/dist/local-editor-viewport-render-coordinator.js +102 -0
- package/dist/local-editor-viewport-render-coordinator.js.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/editor-sky.d.ts +2 -0
- package/node_modules/@fps-games/editor-babylon/dist/editor-sky.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/editor-sky.js +9 -3
- package/node_modules/@fps-games/editor-babylon/dist/editor-sky.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/editor-world.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/editor-world.js +2 -0
- package/node_modules/@fps-games/editor-babylon/dist/editor-world.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/index.d.ts +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/index.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/index.js +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/index.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/infinite-grid.d.ts +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/infinite-grid.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/infinite-grid.js +335 -32
- package/node_modules/@fps-games/editor-babylon/dist/infinite-grid.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/main-camera-preview.d.ts +25 -0
- package/node_modules/@fps-games/editor-babylon/dist/main-camera-preview.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/main-camera-preview.js +162 -0
- package/node_modules/@fps-games/editor-babylon/dist/main-camera-preview.js.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts +28 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/projection.js +169 -25
- package/node_modules/@fps-games/editor-babylon/dist/projection.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/scene-camera-preview.d.ts +2 -22
- package/node_modules/@fps-games/editor-babylon/dist/scene-camera-preview.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/scene-camera-preview.js +1 -121
- package/node_modules/@fps-games/editor-babylon/dist/scene-camera-preview.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.d.ts +4 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.js +37 -23
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-camera-controller.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-input-controller.d.ts +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-input-controller.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-input-controller.js +100 -8
- package/node_modules/@fps-games/editor-babylon/dist/scene-view-input-controller.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.d.ts +6 -1
- package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.js +172 -106
- package/node_modules/@fps-games/editor-babylon/dist/transform-gizmo-controller.js.map +1 -1
- package/node_modules/@fps-games/editor-babylon/dist/transform-solver.d.ts +30 -0
- package/node_modules/@fps-games/editor-babylon/dist/transform-solver.d.ts.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/transform-solver.js +120 -0
- package/node_modules/@fps-games/editor-babylon/dist/transform-solver.js.map +1 -0
- package/node_modules/@fps-games/editor-babylon/dist/types.d.ts +2 -0
- package/node_modules/@fps-games/editor-babylon/dist/types.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-babylon/package.json +4 -4
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.d.ts +2 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.js +167 -34
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-actions.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.d.ts +2 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.js +105 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-controller.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.d.ts +3 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.js +49 -4
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-hierarchy-view.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-input-router.d.ts +4 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-input-router.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-input-router.js +12 -3
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-input-router.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js +96 -14
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-panels.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.js +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shared.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shortcuts.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shortcuts.js +7 -6
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-shortcuts.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-tooltip.js +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts +59 -2
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-types.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.d.ts +1 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.js +3 -0
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui-workbench.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts +5 -2
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js +260 -40
- package/node_modules/@fps-games/editor-browser/dist/local-editor-ui.js.map +1 -1
- package/node_modules/@fps-games/editor-browser/package.json +2 -2
- package/node_modules/@fps-games/editor-core/dist/scene-view-input.d.ts +7 -0
- package/node_modules/@fps-games/editor-core/dist/scene-view-input.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/transform-gizmo.d.ts +22 -0
- package/node_modules/@fps-games/editor-core/dist/transform-gizmo.d.ts.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/transform-gizmo.js.map +1 -1
- package/node_modules/@fps-games/editor-core/dist/viewport-tools.d.ts +6 -6
- package/node_modules/@fps-games/editor-core/dist/viewport-tools.js +3 -3
- package/node_modules/@fps-games/editor-core/dist/viewport-tools.js.map +1 -1
- package/node_modules/@fps-games/editor-core/package.json +2 -2
- package/node_modules/@fps-games/editor-forge-play/package.json +2 -2
- package/node_modules/@fps-games/editor-protocol/package.json +1 -1
- package/package.json +6 -6
|
@@ -5,6 +5,7 @@ import { createLocalEditorTooltipController } from './local-editor-ui-tooltip';
|
|
|
5
5
|
import { DEFAULT_EDITOR_TRANSFORM_OPERATION_SETTINGS, DEFAULT_EDITOR_TRANSFORM_TOOL_DESCRIPTORS, } from '@fps-games/editor-core';
|
|
6
6
|
export { createLocalEditorHierarchyBlankMenu, createLocalEditorHierarchyCopyShortcutAction, createLocalEditorHierarchyDeleteShortcutAction, createLocalEditorHierarchyDuplicateShortcutAction, createLocalEditorHierarchyNodeMenu, createLocalEditorHierarchyPasteShortcutAction, createLocalEditorHierarchySelectAllShortcutAction, } from './local-editor-ui-hierarchy-actions';
|
|
7
7
|
export { createLocalEditorHierarchyController, } from './local-editor-ui-hierarchy-controller';
|
|
8
|
+
export { resolveLocalEditorHierarchySearchRows, } from './local-editor-ui-hierarchy-view';
|
|
8
9
|
export { canLocalEditorHierarchyNodeHaveChildren, createLocalEditorHierarchyTreeModel, isLocalEditorHierarchyNodeMovable, } from './local-editor-ui-hierarchy-tree';
|
|
9
10
|
export { createLocalEditorContextMenuController, } from './local-editor-ui-context-menu';
|
|
10
11
|
export { createLocalEditorTooltipController, } from './local-editor-ui-tooltip';
|
|
@@ -15,14 +16,33 @@ import { createShortcutHelpPanel as createLocalEditorShortcutHelpPanel } from '.
|
|
|
15
16
|
import { applyLocalEditorTheme, ensureLocalEditorTheme, LOCAL_EDITOR_THEME_CLASS, normalizeLocalEditorThemeName, } from './local-editor-ui-theme';
|
|
16
17
|
import { createDefaultLocalEditorWorkbenchLayout, createLocalEditorWorkbenchLayoutController, createLocalEditorWorkbench, createSceneHeaderToolbar, createWorkbenchPanelContent, } from './local-editor-ui-workbench';
|
|
17
18
|
import { createLocalEditorIcon } from './local-editor-ui-icons';
|
|
18
|
-
export { applyLocalEditorBrowserInspectorControlBinding, createLocalEditorBrowserInspectorControlRegistry, formatLocalEditorBrowserInspectorValue, resolveLocalEditorBrowserInspectorSectionStatus, resolveLocalEditorBrowserInspectorControlRegistration, } from './local-editor-ui-panels';
|
|
19
|
+
export { applyLocalEditorBrowserInspectorControlBinding, createLocalEditorBrowserInspectorControlRegistry, formatLocalEditorBrowserInspectorNumberValue, formatLocalEditorBrowserInspectorValue, resolveLocalEditorBrowserInspectorSectionStatus, resolveLocalEditorBrowserInspectorControlRegistration, } from './local-editor-ui-panels';
|
|
19
20
|
export { DEFAULT_LOCAL_EDITOR_THEME, LOCAL_EDITOR_THEME_CLASS, applyLocalEditorTheme, normalizeLocalEditorThemeName, } from './local-editor-ui-theme';
|
|
20
21
|
export { LOCAL_EDITOR_ICON_NAMES, createLocalEditorIcon, isLocalEditorIconName, resolveLocalEditorIconName, } from './local-editor-ui-icons';
|
|
21
|
-
|
|
22
|
+
const INSPECTOR_INPUT_PENDING = Symbol('inspector-input-pending');
|
|
23
|
+
export function parseLocalEditorBrowserInspectorNumberValue(value, mode = 'final') {
|
|
24
|
+
const normalized = value.trim();
|
|
25
|
+
if (normalized === '')
|
|
26
|
+
return mode === 'final' ? 0 : null;
|
|
27
|
+
if (normalized === '-'
|
|
28
|
+
|| normalized === '+'
|
|
29
|
+
|| normalized === '.'
|
|
30
|
+
|| normalized === '-.'
|
|
31
|
+
|| normalized === '+.') {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
if (mode === 'live' && (/[.]$/.test(normalized) || /e[+-]?$/i.test(normalized)))
|
|
35
|
+
return null;
|
|
36
|
+
if (!/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i.test(normalized))
|
|
37
|
+
return null;
|
|
38
|
+
const numeric = Number(normalized);
|
|
39
|
+
return Number.isFinite(numeric) ? numeric : null;
|
|
40
|
+
}
|
|
41
|
+
function readInspectorInputValue(input, mode = 'final') {
|
|
22
42
|
const control = input.dataset.serializedControl;
|
|
23
43
|
const valueType = input.dataset.serializedValueType;
|
|
24
44
|
if ((control === 'vec2' || control === 'vec3') && input instanceof HTMLInputElement) {
|
|
25
|
-
return readInspectorVectorInputValue(input);
|
|
45
|
+
return readInspectorVectorInputValue(input, mode);
|
|
26
46
|
}
|
|
27
47
|
if (control === 'enum' && input instanceof HTMLSelectElement) {
|
|
28
48
|
const option = input.selectedOptions.item(0);
|
|
@@ -40,8 +60,9 @@ function readInspectorInputValue(input) {
|
|
|
40
60
|
return input.checked;
|
|
41
61
|
if (control === 'boolean' || valueType === 'boolean')
|
|
42
62
|
return input.value === 'true';
|
|
43
|
-
if (control === 'number' || valueType === 'number')
|
|
44
|
-
return
|
|
63
|
+
if (control === 'number' || valueType === 'number') {
|
|
64
|
+
return parseLocalEditorBrowserInspectorNumberValue(input.value, mode) ?? INSPECTOR_INPUT_PENDING;
|
|
65
|
+
}
|
|
45
66
|
if (control === 'color' && input instanceof HTMLInputElement && input.type === 'color') {
|
|
46
67
|
const value = input.value.replace('#', '');
|
|
47
68
|
const numeric = Number.parseInt(value, 16);
|
|
@@ -148,7 +169,7 @@ function setToolbarButtonIcon(doc, button, icon) {
|
|
|
148
169
|
else
|
|
149
170
|
button.prepend(nextIcon);
|
|
150
171
|
}
|
|
151
|
-
function readInspectorVectorInputValue(input) {
|
|
172
|
+
function readInspectorVectorInputValue(input, mode) {
|
|
152
173
|
const wrapper = input.closest('[data-inspector-vector-control]');
|
|
153
174
|
const values = {};
|
|
154
175
|
const fields = wrapper
|
|
@@ -158,22 +179,27 @@ function readInspectorVectorInputValue(input) {
|
|
|
158
179
|
const axis = field.dataset.serializedVectorAxis;
|
|
159
180
|
if (!axis)
|
|
160
181
|
continue;
|
|
161
|
-
const numeric =
|
|
162
|
-
|
|
182
|
+
const numeric = parseLocalEditorBrowserInspectorNumberValue(field.value, mode);
|
|
183
|
+
if (numeric == null)
|
|
184
|
+
return INSPECTOR_INPUT_PENDING;
|
|
185
|
+
values[axis] = numeric;
|
|
163
186
|
}
|
|
164
187
|
return values;
|
|
165
188
|
}
|
|
166
|
-
function createInspectorPropertyInput(input, source) {
|
|
189
|
+
function createInspectorPropertyInput(input, source, numberParseMode = 'final') {
|
|
167
190
|
if (!input.dataset.serializedPath || !input.dataset.serializedTargetId)
|
|
168
191
|
return null;
|
|
169
192
|
const targetIds = input.dataset.serializedTargetIds
|
|
170
193
|
? input.dataset.serializedTargetIds.split(',').filter(Boolean)
|
|
171
194
|
: undefined;
|
|
195
|
+
const value = readInspectorInputValue(input, numberParseMode);
|
|
196
|
+
if (value === INSPECTOR_INPUT_PENDING)
|
|
197
|
+
return null;
|
|
172
198
|
return {
|
|
173
199
|
targetId: input.dataset.serializedTargetId,
|
|
174
200
|
targetIds,
|
|
175
201
|
path: input.dataset.serializedPath,
|
|
176
|
-
value
|
|
202
|
+
value,
|
|
177
203
|
control: input.dataset.serializedControl,
|
|
178
204
|
valueType: input.dataset.serializedValueType,
|
|
179
205
|
commitMode: input.dataset.serializedCommitMode,
|
|
@@ -181,6 +207,13 @@ function createInspectorPropertyInput(input, source) {
|
|
|
181
207
|
source: input.dataset.serializedEditSource ?? source,
|
|
182
208
|
};
|
|
183
209
|
}
|
|
210
|
+
function hasPendingInspectorNumberValue(input, mode = 'live') {
|
|
211
|
+
const control = input.dataset.serializedControl;
|
|
212
|
+
const valueType = input.dataset.serializedValueType;
|
|
213
|
+
if (control !== 'number' && valueType !== 'number' && control !== 'vec2' && control !== 'vec3')
|
|
214
|
+
return false;
|
|
215
|
+
return readInspectorInputValue(input, mode) === INSPECTOR_INPUT_PENDING;
|
|
216
|
+
}
|
|
184
217
|
function readInspectorCommitMode(input) {
|
|
185
218
|
return input.dataset.serializedCommitMode ?? 'live';
|
|
186
219
|
}
|
|
@@ -193,6 +226,96 @@ function readInspectorImmediateSource(input) {
|
|
|
193
226
|
return 'color';
|
|
194
227
|
return 'input';
|
|
195
228
|
}
|
|
229
|
+
function createSceneFrameRateOverlay(doc) {
|
|
230
|
+
const root = doc.createElement('div');
|
|
231
|
+
root.classList.add(LOCAL_EDITOR_THEME_CLASS);
|
|
232
|
+
root.dataset.editorSceneFrameRateOverlay = 'true';
|
|
233
|
+
root.style.cssText = [
|
|
234
|
+
'position:absolute',
|
|
235
|
+
'right:14px',
|
|
236
|
+
'bottom:134px',
|
|
237
|
+
'z-index:3',
|
|
238
|
+
'display:none',
|
|
239
|
+
'align-items:center',
|
|
240
|
+
'gap:6px',
|
|
241
|
+
'width:112px',
|
|
242
|
+
'height:30px',
|
|
243
|
+
'padding:0 8px',
|
|
244
|
+
'box-sizing:border-box',
|
|
245
|
+
'border:1px solid color-mix(in srgb, var(--fps-editor-border) 78%, transparent)',
|
|
246
|
+
'border-radius:6px',
|
|
247
|
+
'background:color-mix(in srgb, var(--fps-editor-chrome) 76%, transparent)',
|
|
248
|
+
'box-shadow:var(--fps-editor-shadow-panel)',
|
|
249
|
+
'font-family:var(--fps-editor-font)',
|
|
250
|
+
'font-size:11px',
|
|
251
|
+
'font-weight:900',
|
|
252
|
+
'letter-spacing:0',
|
|
253
|
+
'color:var(--fps-editor-text-strong)',
|
|
254
|
+
'pointer-events:none',
|
|
255
|
+
'backdrop-filter:blur(5px)',
|
|
256
|
+
'overflow:hidden',
|
|
257
|
+
].join(';');
|
|
258
|
+
const label = doc.createElement('span');
|
|
259
|
+
label.textContent = 'FPS';
|
|
260
|
+
label.style.cssText = [
|
|
261
|
+
'color:var(--fps-editor-muted-strong)',
|
|
262
|
+
'font-size:10px',
|
|
263
|
+
'line-height:1',
|
|
264
|
+
].join(';');
|
|
265
|
+
const fpsValue = doc.createElement('span');
|
|
266
|
+
fpsValue.textContent = '--';
|
|
267
|
+
fpsValue.style.cssText = [
|
|
268
|
+
'width:26px',
|
|
269
|
+
'flex:0 0 26px',
|
|
270
|
+
'font-variant-numeric:tabular-nums',
|
|
271
|
+
'font-size:13px',
|
|
272
|
+
'line-height:1',
|
|
273
|
+
].join(';');
|
|
274
|
+
const modeLabel = doc.createElement('span');
|
|
275
|
+
modeLabel.textContent = 'IDLE';
|
|
276
|
+
modeLabel.style.cssText = [
|
|
277
|
+
'margin-left:auto',
|
|
278
|
+
'padding:2px 4px',
|
|
279
|
+
'flex:0 0 auto',
|
|
280
|
+
'border:1px solid var(--fps-editor-border-soft)',
|
|
281
|
+
'border-radius:4px',
|
|
282
|
+
'background:color-mix(in srgb, var(--fps-editor-field) 72%, transparent)',
|
|
283
|
+
'color:var(--fps-editor-muted)',
|
|
284
|
+
'font-size:9px',
|
|
285
|
+
'line-height:1',
|
|
286
|
+
].join(';');
|
|
287
|
+
root.appendChild(label);
|
|
288
|
+
root.appendChild(fpsValue);
|
|
289
|
+
root.appendChild(modeLabel);
|
|
290
|
+
return { root, fpsValue, modeLabel };
|
|
291
|
+
}
|
|
292
|
+
function renderSceneFrameRateOverlay(overlay, stats) {
|
|
293
|
+
if (!stats) {
|
|
294
|
+
overlay.root.style.display = 'none';
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
overlay.root.style.display = 'flex';
|
|
298
|
+
const fps = Number.isFinite(stats.fps) ? Math.round(stats.fps) : null;
|
|
299
|
+
const displayFps = stats.mode === 'idle' ? 0 : fps;
|
|
300
|
+
overlay.fpsValue.textContent = displayFps == null ? '--' : String(displayFps);
|
|
301
|
+
overlay.modeLabel.textContent = stats.mode === 'continuous' ? 'LIVE' : 'IDLE';
|
|
302
|
+
overlay.modeLabel.style.color = stats.mode === 'continuous'
|
|
303
|
+
? 'var(--fps-editor-success)'
|
|
304
|
+
: 'var(--fps-editor-muted)';
|
|
305
|
+
overlay.fpsValue.style.color = displayFps == null || stats.mode === 'idle'
|
|
306
|
+
? 'var(--fps-editor-muted)'
|
|
307
|
+
: displayFps >= 50
|
|
308
|
+
? 'var(--fps-editor-success)'
|
|
309
|
+
: displayFps >= 30
|
|
310
|
+
? 'var(--fps-editor-warn)'
|
|
311
|
+
: 'var(--fps-editor-danger-strong)';
|
|
312
|
+
overlay.root.title = [
|
|
313
|
+
`Scene FPS: ${displayFps == null ? '--' : displayFps}`,
|
|
314
|
+
`mode: ${stats.mode}`,
|
|
315
|
+
stats.lastFrameMs == null ? '' : `frame: ${stats.lastFrameMs.toFixed(1)}ms`,
|
|
316
|
+
stats.activeReasons.length ? `active: ${stats.activeReasons.join(', ')}` : '',
|
|
317
|
+
].filter(Boolean).join(' | ');
|
|
318
|
+
}
|
|
196
319
|
function createCoordinateAxesOverlay(doc) {
|
|
197
320
|
const root = doc.createElement('div');
|
|
198
321
|
root.dataset.editorCoordinateAxesOverlay = 'true';
|
|
@@ -260,6 +383,30 @@ function createCoordinateAxesOverlay(doc) {
|
|
|
260
383
|
centerDot.setAttribute('r', '3.2');
|
|
261
384
|
centerDot.setAttribute('fill', 'color-mix(in srgb, var(--fps-editor-text) 82%, transparent)');
|
|
262
385
|
labelLayer.appendChild(centerDot);
|
|
386
|
+
const projectionIcon = doc.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
387
|
+
projectionIcon.setAttribute('transform', 'translate(8 8)');
|
|
388
|
+
projectionIcon.setAttribute('role', 'button');
|
|
389
|
+
projectionIcon.setAttribute('tabindex', '0');
|
|
390
|
+
projectionIcon.dataset.coordinateAxesProjectionToggle = 'true';
|
|
391
|
+
projectionIcon.style.cssText = 'opacity:0.92;pointer-events:auto;cursor:pointer;outline:none';
|
|
392
|
+
const projectionIconFrame = doc.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
|
393
|
+
projectionIconFrame.setAttribute('x', '0');
|
|
394
|
+
projectionIconFrame.setAttribute('y', '0');
|
|
395
|
+
projectionIconFrame.setAttribute('width', '18');
|
|
396
|
+
projectionIconFrame.setAttribute('height', '18');
|
|
397
|
+
projectionIconFrame.setAttribute('rx', '4');
|
|
398
|
+
projectionIconFrame.setAttribute('fill', 'color-mix(in srgb, var(--fps-editor-chrome) 78%, transparent)');
|
|
399
|
+
projectionIconFrame.setAttribute('stroke', 'color-mix(in srgb, var(--fps-editor-border) 82%, transparent)');
|
|
400
|
+
projectionIconFrame.setAttribute('stroke-width', '1');
|
|
401
|
+
const projectionIconShape = doc.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
402
|
+
projectionIconShape.setAttribute('fill', 'none');
|
|
403
|
+
projectionIconShape.setAttribute('stroke', 'color-mix(in srgb, var(--fps-editor-accent) 82%, #ffffff)');
|
|
404
|
+
projectionIconShape.setAttribute('stroke-width', '1.6');
|
|
405
|
+
projectionIconShape.setAttribute('stroke-linejoin', 'round');
|
|
406
|
+
projectionIconShape.setAttribute('stroke-linecap', 'round');
|
|
407
|
+
projectionIcon.appendChild(projectionIconFrame);
|
|
408
|
+
projectionIcon.appendChild(projectionIconShape);
|
|
409
|
+
svg.appendChild(projectionIcon);
|
|
263
410
|
return {
|
|
264
411
|
root,
|
|
265
412
|
lineLayer,
|
|
@@ -269,6 +416,8 @@ function createCoordinateAxesOverlay(doc) {
|
|
|
269
416
|
axisLabels,
|
|
270
417
|
axisDiscs,
|
|
271
418
|
centerDot,
|
|
419
|
+
projectionIcon,
|
|
420
|
+
projectionIconShape,
|
|
272
421
|
};
|
|
273
422
|
}
|
|
274
423
|
function renderCoordinateAxesOverlay(overlay, state) {
|
|
@@ -277,6 +426,7 @@ function renderCoordinateAxesOverlay(overlay, state) {
|
|
|
277
426
|
return;
|
|
278
427
|
}
|
|
279
428
|
overlay.root.style.display = '';
|
|
429
|
+
renderCoordinateAxesProjectionIcon(overlay, state.projectionMode, state.projectionToggleDisabled === true);
|
|
280
430
|
const center = 56;
|
|
281
431
|
const lineLength = 38;
|
|
282
432
|
const sortedAxes = [...state.axes].sort((left, right) => right.depth - left.depth);
|
|
@@ -305,6 +455,18 @@ function renderCoordinateAxesOverlay(overlay, state) {
|
|
|
305
455
|
}
|
|
306
456
|
overlay.labelLayer.appendChild(overlay.centerDot);
|
|
307
457
|
}
|
|
458
|
+
function renderCoordinateAxesProjectionIcon(overlay, mode, disabled) {
|
|
459
|
+
overlay.projectionIcon.dataset.viewportProjectionMode = mode;
|
|
460
|
+
overlay.projectionIcon.setAttribute('aria-label', disabled
|
|
461
|
+
? `编辑视口投影:${VIEWPORT_PROJECTION_LABELS[mode]},Main Camera 预览中不可切换`
|
|
462
|
+
: `编辑视口投影:${VIEWPORT_PROJECTION_LABELS[mode]},点击切换`);
|
|
463
|
+
overlay.projectionIcon.setAttribute('aria-disabled', disabled ? 'true' : 'false');
|
|
464
|
+
overlay.projectionIcon.style.opacity = disabled ? '0.46' : '0.92';
|
|
465
|
+
overlay.projectionIcon.style.cursor = disabled ? 'not-allowed' : 'pointer';
|
|
466
|
+
overlay.projectionIconShape.setAttribute('d', mode === 'orthographic'
|
|
467
|
+
? 'M5 6.5H12.5V14H5ZM7.5 4H15V11.5'
|
|
468
|
+
: 'M4.5 14H13.5L10.5 4H7.5ZM7 10.5H11');
|
|
469
|
+
}
|
|
308
470
|
function createSpatialOverlay(doc) {
|
|
309
471
|
const root = doc.createElement('div');
|
|
310
472
|
root.classList.add(LOCAL_EDITOR_THEME_CLASS);
|
|
@@ -571,7 +733,9 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
571
733
|
const localTestActionsEnabled = options.localTestActions === true;
|
|
572
734
|
ensureLocalEditorTheme(doc);
|
|
573
735
|
let activeTheme = normalizeLocalEditorThemeName(options.theme);
|
|
574
|
-
const inputRouter = createLocalEditorWorkbenchInputRouter(doc
|
|
736
|
+
const inputRouter = createLocalEditorWorkbenchInputRouter(doc, {
|
|
737
|
+
isShortcutReserved: options.input?.isShortcutReserved,
|
|
738
|
+
});
|
|
575
739
|
const contextMenu = createLocalEditorContextMenuController(doc, (open) => {
|
|
576
740
|
inputRouter.setContextMenuOpen(open);
|
|
577
741
|
}, activeTheme);
|
|
@@ -959,17 +1123,17 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
959
1123
|
sceneUtilityActions.appendChild(gridToggleButton);
|
|
960
1124
|
sceneUtilityActions.appendChild(themeToggleButton);
|
|
961
1125
|
sceneUtilityActions.appendChild(sceneHelpButton);
|
|
962
|
-
const
|
|
963
|
-
|
|
1126
|
+
const mainCameraPreviewGroup = doc.createElement('div');
|
|
1127
|
+
mainCameraPreviewGroup.style.cssText = [
|
|
964
1128
|
'display:flex',
|
|
965
1129
|
'align-items:center',
|
|
966
1130
|
'gap:4px',
|
|
967
1131
|
'padding-left:8px',
|
|
968
1132
|
'border-left:1px solid var(--fps-editor-divider)',
|
|
969
1133
|
].join(';');
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
|
|
1134
|
+
const mainCameraPreviewButton = createToolbarIconButton(doc, '从 Main Camera 查看场景', 'camera');
|
|
1135
|
+
mainCameraPreviewButton.dataset.mainCameraPreviewToggle = 'true';
|
|
1136
|
+
mainCameraPreviewGroup.appendChild(mainCameraPreviewButton);
|
|
973
1137
|
const viewportToolsGroup = doc.createElement('div');
|
|
974
1138
|
viewportToolsGroup.style.cssText = [
|
|
975
1139
|
'display:flex',
|
|
@@ -1062,6 +1226,7 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1062
1226
|
'pointer-events:auto',
|
|
1063
1227
|
].join(';');
|
|
1064
1228
|
const coordinateAxesOverlay = createCoordinateAxesOverlay(doc);
|
|
1229
|
+
const sceneFrameRateOverlay = createSceneFrameRateOverlay(doc);
|
|
1065
1230
|
const spatialOverlay = createSpatialOverlay(doc);
|
|
1066
1231
|
const measurementOverlay = createMeasurementOverlay(doc);
|
|
1067
1232
|
sceneToolOverlay.appendChild(sceneTitle);
|
|
@@ -1073,12 +1238,13 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1073
1238
|
sceneToolOverlay.appendChild(actionGroup);
|
|
1074
1239
|
sceneToolOverlay.appendChild(viewportToolsGroup);
|
|
1075
1240
|
sceneToolOverlay.appendChild(sceneUtilityActions);
|
|
1076
|
-
sceneToolOverlay.appendChild(
|
|
1241
|
+
sceneToolOverlay.appendChild(mainCameraPreviewGroup);
|
|
1077
1242
|
sceneToolOverlay.appendChild(editorStatusButton);
|
|
1078
1243
|
sceneToolOverlay.appendChild(toolbarOverflowButton);
|
|
1079
1244
|
workbench.sceneHeader.appendChild(sceneToolOverlay);
|
|
1080
1245
|
workbench.sceneFrame.appendChild(spatialOverlay.root);
|
|
1081
1246
|
workbench.sceneFrame.appendChild(measurementOverlay.root);
|
|
1247
|
+
workbench.sceneFrame.appendChild(sceneFrameRateOverlay.root);
|
|
1082
1248
|
workbench.sceneFrame.appendChild(coordinateAxesOverlay.root);
|
|
1083
1249
|
root.appendChild(localTestMenu);
|
|
1084
1250
|
root.appendChild(toolbarOverflowMenu);
|
|
@@ -1114,6 +1280,7 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1114
1280
|
applyLocalEditorTheme(workbench.root, activeTheme);
|
|
1115
1281
|
applyLocalEditorTheme(spatialOverlay.root, activeTheme);
|
|
1116
1282
|
applyLocalEditorTheme(measurementOverlay.root, activeTheme);
|
|
1283
|
+
applyLocalEditorTheme(sceneFrameRateOverlay.root, activeTheme);
|
|
1117
1284
|
applyLocalEditorTheme(shortcutHelpPanel, activeTheme);
|
|
1118
1285
|
applyLocalEditorTheme(boxSelectionOverlay, activeTheme);
|
|
1119
1286
|
applyLocalEditorTheme(localTestMenu, activeTheme);
|
|
@@ -1326,14 +1493,14 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1326
1493
|
actionGroup,
|
|
1327
1494
|
viewportToolsGroup,
|
|
1328
1495
|
sceneUtilityActions,
|
|
1329
|
-
|
|
1496
|
+
mainCameraPreviewGroup,
|
|
1330
1497
|
editorStatusButton,
|
|
1331
1498
|
toolbarOverflowButton,
|
|
1332
1499
|
];
|
|
1333
1500
|
const toolbarOverflowItems = [
|
|
1334
1501
|
{ id: 'editor-status', element: editorStatusButton, kind: 'group' },
|
|
1335
1502
|
{ id: 'scene-utilities', element: sceneUtilityActions, kind: 'group' },
|
|
1336
|
-
{ id: 'camera-preview', element:
|
|
1503
|
+
{ id: 'main-camera-preview', element: mainCameraPreviewGroup, kind: 'group' },
|
|
1337
1504
|
{ id: 'viewport-tools', element: viewportToolsGroup, kind: 'group' },
|
|
1338
1505
|
{ id: 'transform-actions', element: actionGroup, kind: 'group' },
|
|
1339
1506
|
{ id: 'placement', element: placementGroup, kind: 'group' },
|
|
@@ -1538,9 +1705,30 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1538
1705
|
const visible = currentState?.grid?.visible ?? true;
|
|
1539
1706
|
callbacks.onGridVisibleChange?.(!visible);
|
|
1540
1707
|
});
|
|
1541
|
-
|
|
1542
|
-
const enabled = currentState?.
|
|
1543
|
-
callbacks.
|
|
1708
|
+
mainCameraPreviewButton.addEventListener('click', () => {
|
|
1709
|
+
const enabled = currentState?.mainCameraPreview?.enabled ?? false;
|
|
1710
|
+
callbacks.onMainCameraPreviewToggle?.(!enabled);
|
|
1711
|
+
});
|
|
1712
|
+
const toggleCoordinateAxesProjection = (event) => {
|
|
1713
|
+
event.preventDefault();
|
|
1714
|
+
event.stopPropagation();
|
|
1715
|
+
const axesState = currentState?.coordinateAxes ?? null;
|
|
1716
|
+
if (!axesState || axesState.projectionToggleDisabled || currentState?.busy)
|
|
1717
|
+
return;
|
|
1718
|
+
const currentMode = axesState.projectionMode;
|
|
1719
|
+
const nextMode = currentMode === 'orthographic' ? 'perspective' : 'orthographic';
|
|
1720
|
+
callbacks.onViewportProjectionModeChange?.(nextMode);
|
|
1721
|
+
if (event.type === 'click')
|
|
1722
|
+
coordinateAxesOverlay.projectionIcon.blur();
|
|
1723
|
+
};
|
|
1724
|
+
coordinateAxesOverlay.projectionIcon.addEventListener('pointerdown', (event) => {
|
|
1725
|
+
event.preventDefault();
|
|
1726
|
+
});
|
|
1727
|
+
coordinateAxesOverlay.projectionIcon.addEventListener('click', toggleCoordinateAxesProjection);
|
|
1728
|
+
coordinateAxesOverlay.projectionIcon.addEventListener('keydown', (event) => {
|
|
1729
|
+
if (event.key !== 'Enter' && event.key !== ' ')
|
|
1730
|
+
return;
|
|
1731
|
+
toggleCoordinateAxesProjection(event);
|
|
1544
1732
|
});
|
|
1545
1733
|
viewportToolsGroup.addEventListener('click', (event) => {
|
|
1546
1734
|
const target = event.target instanceof HTMLElement ? event.target : null;
|
|
@@ -1666,10 +1854,10 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1666
1854
|
return;
|
|
1667
1855
|
const currentOverlay = currentState?.viewportTools?.overlay;
|
|
1668
1856
|
callbacks.onViewportOverlaySettingsChange?.({
|
|
1669
|
-
bounds: currentOverlay?.bounds ??
|
|
1670
|
-
dimensions: currentOverlay?.dimensions ??
|
|
1857
|
+
bounds: currentOverlay?.bounds ?? false,
|
|
1858
|
+
dimensions: currentOverlay?.dimensions ?? false,
|
|
1671
1859
|
edgeLengths: currentOverlay?.edgeLengths ?? false,
|
|
1672
|
-
anchor: currentOverlay?.anchor ??
|
|
1860
|
+
anchor: currentOverlay?.anchor ?? false,
|
|
1673
1861
|
[key]: input.checked,
|
|
1674
1862
|
});
|
|
1675
1863
|
});
|
|
@@ -1696,6 +1884,7 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1696
1884
|
inputRouter,
|
|
1697
1885
|
contextMenu,
|
|
1698
1886
|
getState: () => currentState,
|
|
1887
|
+
contextActions: options.hierarchy?.contextActions,
|
|
1699
1888
|
requestRender: () => {
|
|
1700
1889
|
if (currentState)
|
|
1701
1890
|
render(currentState);
|
|
@@ -1725,7 +1914,7 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1725
1914
|
return;
|
|
1726
1915
|
if (readInspectorCommitMode(input) !== 'live')
|
|
1727
1916
|
return;
|
|
1728
|
-
const propertyInput = createInspectorPropertyInput(input, 'input');
|
|
1917
|
+
const propertyInput = createInspectorPropertyInput(input, 'input', 'live');
|
|
1729
1918
|
if (propertyInput)
|
|
1730
1919
|
callbacks.onPropertyInput?.(propertyInput);
|
|
1731
1920
|
});
|
|
@@ -1739,7 +1928,7 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1739
1928
|
if (readInspectorCommitMode(input) !== 'change')
|
|
1740
1929
|
return;
|
|
1741
1930
|
}
|
|
1742
|
-
const propertyInput = createInspectorPropertyInput(input, readInspectorImmediateSource(input));
|
|
1931
|
+
const propertyInput = createInspectorPropertyInput(input, readInspectorImmediateSource(input), 'final');
|
|
1743
1932
|
if (propertyInput)
|
|
1744
1933
|
callbacks.onPropertyInput?.(propertyInput);
|
|
1745
1934
|
});
|
|
@@ -1747,11 +1936,27 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1747
1936
|
const input = event.target instanceof HTMLInputElement ? event.target : null;
|
|
1748
1937
|
if (!input?.dataset.serializedPath || !input.dataset.serializedTargetId)
|
|
1749
1938
|
return;
|
|
1750
|
-
if (
|
|
1939
|
+
if (hasPendingInspectorNumberValue(input, 'final')) {
|
|
1940
|
+
if (currentState)
|
|
1941
|
+
render(currentState);
|
|
1751
1942
|
return;
|
|
1752
|
-
|
|
1943
|
+
}
|
|
1944
|
+
const commitMode = readInspectorCommitMode(input);
|
|
1945
|
+
if (commitMode === 'live' && hasPendingInspectorNumberValue(input, 'live')) {
|
|
1946
|
+
const propertyInput = createInspectorPropertyInput(input, 'input', 'final');
|
|
1947
|
+
if (propertyInput)
|
|
1948
|
+
callbacks.onPropertyInput?.(propertyInput);
|
|
1949
|
+
else if (currentState)
|
|
1950
|
+
render(currentState);
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
if (commitMode !== 'blur')
|
|
1954
|
+
return;
|
|
1955
|
+
const propertyInput = createInspectorPropertyInput(input, 'input', 'final');
|
|
1753
1956
|
if (propertyInput)
|
|
1754
1957
|
callbacks.onPropertyInput?.(propertyInput);
|
|
1958
|
+
else if (currentState)
|
|
1959
|
+
render(currentState);
|
|
1755
1960
|
});
|
|
1756
1961
|
const onKeyDown = (event) => {
|
|
1757
1962
|
if (event.defaultPrevented)
|
|
@@ -1848,11 +2053,15 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1848
2053
|
`[data-serialized-target-id="${cssEscape(active.dataset.serializedTargetId)}"]`,
|
|
1849
2054
|
].join(''),
|
|
1850
2055
|
value: active.value,
|
|
2056
|
+
preserveValue: hasPendingInspectorNumberValue(active),
|
|
1851
2057
|
};
|
|
1852
2058
|
}
|
|
1853
2059
|
if (active.dataset.editorInspectorSearch != null) {
|
|
1854
2060
|
return { selector: 'input[data-editor-inspector-search]', value: active.value };
|
|
1855
2061
|
}
|
|
2062
|
+
if (active.dataset.editorHierarchySearch != null) {
|
|
2063
|
+
return { selector: 'input[data-editor-hierarchy-search]', value: active.value };
|
|
2064
|
+
}
|
|
1856
2065
|
if (active.dataset.editorAssetFilter != null) {
|
|
1857
2066
|
return { selector: 'input[data-editor-asset-filter]', value: active.value };
|
|
1858
2067
|
}
|
|
@@ -1865,6 +2074,8 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1865
2074
|
if (!input)
|
|
1866
2075
|
return;
|
|
1867
2076
|
input.focus({ preventScroll: true });
|
|
2077
|
+
if (snapshot.value != null && snapshot.preserveValue)
|
|
2078
|
+
input.value = snapshot.value;
|
|
1868
2079
|
if (snapshot.value != null && input.value === snapshot.value) {
|
|
1869
2080
|
const position = input.value.length;
|
|
1870
2081
|
try {
|
|
@@ -1902,7 +2113,7 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1902
2113
|
contextMenu.close();
|
|
1903
2114
|
hostChrome.style.display = !inEditor && localTestActionsEnabled ? 'flex' : 'none';
|
|
1904
2115
|
enterEditorButton.disabled = disabled;
|
|
1905
|
-
for (const button of [saveButton, saveAndRunButton, discardRunButton, undoButton, redoButton, sceneHelpButton,
|
|
2116
|
+
for (const button of [saveButton, saveAndRunButton, discardRunButton, undoButton, redoButton, sceneHelpButton, mainCameraPreviewButton, gridToggleButton]) {
|
|
1906
2117
|
button.style.display = 'inline-flex';
|
|
1907
2118
|
button.disabled = disabled;
|
|
1908
2119
|
}
|
|
@@ -1915,6 +2126,8 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1915
2126
|
inputRouter.setModalOpen(inEditor && helpOpen);
|
|
1916
2127
|
const transformTool = state.transformTool ?? null;
|
|
1917
2128
|
workbench.root.style.display = inEditor ? '' : 'none';
|
|
2129
|
+
if (inEditor)
|
|
2130
|
+
workbenchLayoutController.refresh();
|
|
1918
2131
|
sceneToolOverlay.style.display = inEditor ? 'flex' : 'none';
|
|
1919
2132
|
if (!inEditor)
|
|
1920
2133
|
closeSnapSettingsPopover();
|
|
@@ -1924,18 +2137,21 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1924
2137
|
closeTransformActionPopover();
|
|
1925
2138
|
if (!inEditor)
|
|
1926
2139
|
closeOverlaySettingsPopover();
|
|
1927
|
-
const
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
const
|
|
2140
|
+
const mainCameraPreview = state.mainCameraPreview ?? { enabled: false, available: false };
|
|
2141
|
+
mainCameraPreviewGroup.style.display = inEditor ? 'flex' : 'none';
|
|
2142
|
+
mainCameraPreviewButton.disabled = disabled || !mainCameraPreview.available;
|
|
2143
|
+
const mainCameraPreviewTooltip = mainCameraPreview.available
|
|
1931
2144
|
? '从 Main Camera 查看当前场景'
|
|
1932
2145
|
: '当前场景没有可预览的 Main Camera';
|
|
1933
|
-
setToolbarButtonTooltip(
|
|
1934
|
-
LocalEditorShared.applyButtonActiveState(
|
|
2146
|
+
setToolbarButtonTooltip(mainCameraPreviewButton, mainCameraPreviewTooltip);
|
|
2147
|
+
LocalEditorShared.applyButtonActiveState(mainCameraPreviewButton, mainCameraPreview.enabled);
|
|
1935
2148
|
const viewportTools = state.viewportTools ?? null;
|
|
1936
|
-
const viewportControlsDisabled = disabled ||
|
|
1937
|
-
const viewportControlsTooltip =
|
|
1938
|
-
? '
|
|
2149
|
+
const viewportControlsDisabled = disabled || mainCameraPreview.enabled;
|
|
2150
|
+
const viewportControlsTooltip = mainCameraPreview.enabled
|
|
2151
|
+
? '当前为 Main Camera 预览,请关闭后再使用视口工具'
|
|
2152
|
+
: '';
|
|
2153
|
+
const viewportProjectionTooltip = mainCameraPreview.enabled
|
|
2154
|
+
? '当前为 Main Camera 预览,投影由 Main Camera 决定;关闭预览后可切换编辑视口投影'
|
|
1939
2155
|
: '';
|
|
1940
2156
|
viewportToolsGroup.style.display = inEditor ? 'flex' : 'none';
|
|
1941
2157
|
for (const [preset, button] of viewportPresetButtons) {
|
|
@@ -1947,7 +2163,7 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
1947
2163
|
const projectionMode = viewportTools?.projectionMode ?? 'perspective';
|
|
1948
2164
|
const nextProjectionMode = projectionMode === 'orthographic' ? 'perspective' : 'orthographic';
|
|
1949
2165
|
setToolbarButtonIcon(doc, projectionToggleButton, projectionMode === 'orthographic' ? 'projection-ortho' : 'projection-perspective');
|
|
1950
|
-
setToolbarButtonTooltip(projectionToggleButton,
|
|
2166
|
+
setToolbarButtonTooltip(projectionToggleButton, viewportProjectionTooltip || `投影模式:${VIEWPORT_PROJECTION_LABELS[projectionMode]}。切换为${VIEWPORT_PROJECTION_LABELS[nextProjectionMode]}`);
|
|
1951
2167
|
LocalEditorShared.applyButtonActiveState(projectionToggleButton, projectionMode === 'orthographic');
|
|
1952
2168
|
overlaySettingsButton.disabled = disabled;
|
|
1953
2169
|
setToolbarButtonTooltip(overlaySettingsButton, '视口信息层设置');
|
|
@@ -2059,6 +2275,7 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
2059
2275
|
? 'var(--fps-editor-border)'
|
|
2060
2276
|
: statusToneColor;
|
|
2061
2277
|
renderCoordinateAxesOverlay(coordinateAxesOverlay, inEditor ? state.coordinateAxes ?? null : null);
|
|
2278
|
+
renderSceneFrameRateOverlay(sceneFrameRateOverlay, inEditor ? state.sceneFrameStats ?? null : null);
|
|
2062
2279
|
renderSpatialOverlay(spatialOverlay, inEditor ? state.viewportSpatialOverlay ?? null : null);
|
|
2063
2280
|
renderMeasurementOverlay(measurementOverlay, inEditor ? state.viewportMeasurement ?? null : null);
|
|
2064
2281
|
const boxSelection = state.boxSelection;
|
|
@@ -2088,6 +2305,9 @@ export function createLocalEditorBrowserUi(options = {}) {
|
|
|
2088
2305
|
update(state) {
|
|
2089
2306
|
render(state);
|
|
2090
2307
|
},
|
|
2308
|
+
updateSceneFrameStats(stats) {
|
|
2309
|
+
renderSceneFrameRateOverlay(sceneFrameRateOverlay, currentState?.mode === 'editor' ? stats : null);
|
|
2310
|
+
},
|
|
2091
2311
|
setTheme(theme) {
|
|
2092
2312
|
setActiveTheme(theme);
|
|
2093
2313
|
},
|