@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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_EDITOR_TRANSFORM_OPERATION_SETTINGS, normalizeEditorTransformConstraint, snapEditorTransformSnapshot, } from '@fps-games/editor-core';
|
|
2
|
+
import { createBabylonTransformSolver } from './transform-solver';
|
|
2
3
|
export function resolveBabylonTransformHandleConstraint(tool, handleKey) {
|
|
3
4
|
if (tool === 'move') {
|
|
4
5
|
if (handleKey === 'xPlaneGizmo' || handleKey === 'yPlaneGizmo' || handleKey === 'zPlaneGizmo')
|
|
@@ -18,13 +19,10 @@ export function resolveBabylonTransformHandleConstraint(tool, handleKey) {
|
|
|
18
19
|
return null;
|
|
19
20
|
}
|
|
20
21
|
export function createBabylonTransformGizmoController(options) {
|
|
21
|
-
const
|
|
22
|
-
if (!
|
|
22
|
+
const GizmoManagerCtor = options.babylon.GizmoManager;
|
|
23
|
+
if (!GizmoManagerCtor)
|
|
23
24
|
throw new Error('Babylon runtime missing GizmoManager');
|
|
24
|
-
const
|
|
25
|
-
manager.usePointerToAttachGizmos = false;
|
|
26
|
-
manager.clearGizmoOnEmptyPointerEvent = false;
|
|
27
|
-
manager.boundingBoxGizmoEnabled = false;
|
|
25
|
+
const transformSolver = createBabylonTransformSolver({ babylon: options.babylon });
|
|
28
26
|
let tool = options.initialTool ?? 'select';
|
|
29
27
|
let space = options.initialSpace ?? 'world';
|
|
30
28
|
let constraint = normalizeConstraintForTool(tool, 'axis') ?? 'axis';
|
|
@@ -40,7 +38,17 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
40
38
|
let freeMoveHandleMaterial = null;
|
|
41
39
|
let placementMarker = null;
|
|
42
40
|
let placementMarkerMaterial = null;
|
|
41
|
+
let manager = null;
|
|
43
42
|
const canvas = options.scene.getEngine?.().getRenderingCanvas?.();
|
|
43
|
+
function ensureGizmoManager() {
|
|
44
|
+
if (manager)
|
|
45
|
+
return manager;
|
|
46
|
+
manager = new GizmoManagerCtor(options.scene);
|
|
47
|
+
manager.usePointerToAttachGizmos = false;
|
|
48
|
+
manager.clearGizmoOnEmptyPointerEvent = false;
|
|
49
|
+
manager.boundingBoxGizmoEnabled = false;
|
|
50
|
+
return manager;
|
|
51
|
+
}
|
|
44
52
|
function activeTransformTool() {
|
|
45
53
|
return tool === 'select' ? null : tool;
|
|
46
54
|
}
|
|
@@ -116,25 +124,31 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
116
124
|
if (!activeConstraint)
|
|
117
125
|
continue;
|
|
118
126
|
const behavior = gizmo?.[handleKey]?.dragBehavior;
|
|
119
|
-
addObserver(behavior?.onDragStartObservable, () => beginDrag(activeConstraint));
|
|
127
|
+
addObserver(behavior?.onDragStartObservable, () => beginDrag(activeConstraint, handleKey));
|
|
120
128
|
addObserver(behavior?.onDragObservable, updateDrag);
|
|
121
129
|
addObserver(behavior?.onDragEndObservable, endDrag);
|
|
122
130
|
}
|
|
123
131
|
}
|
|
124
132
|
function registerDragObservers() {
|
|
125
133
|
clearDragObservers();
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
134
|
+
const activeManager = manager;
|
|
135
|
+
if (!activeManager)
|
|
136
|
+
return;
|
|
137
|
+
registerDragObserversFor('move', activeManager.gizmos?.positionGizmo);
|
|
138
|
+
registerDragObserversFor('rotate', activeManager.gizmos?.rotationGizmo);
|
|
139
|
+
registerDragObserversFor('scale', activeManager.gizmos?.scaleGizmo);
|
|
129
140
|
}
|
|
130
141
|
function applySpacePreference() {
|
|
131
|
-
const
|
|
142
|
+
const activeManager = manager;
|
|
143
|
+
if (!activeManager)
|
|
144
|
+
return;
|
|
132
145
|
const gizmos = [
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
146
|
+
{ gizmo: activeManager.gizmos?.positionGizmo },
|
|
147
|
+
{ gizmo: activeManager.gizmos?.rotationGizmo },
|
|
148
|
+
{ gizmo: activeManager.gizmos?.scaleGizmo },
|
|
136
149
|
];
|
|
137
|
-
for (const gizmo of gizmos) {
|
|
150
|
+
for (const { gizmo } of gizmos) {
|
|
151
|
+
const matchAttachedMesh = shouldMatchAttachedMeshForGizmo();
|
|
138
152
|
try {
|
|
139
153
|
if ('updateGizmoRotationToMatchAttachedMesh' in (gizmo ?? {})) {
|
|
140
154
|
gizmo.updateGizmoRotationToMatchAttachedMesh = matchAttachedMesh;
|
|
@@ -159,8 +173,11 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
159
173
|
}
|
|
160
174
|
}
|
|
161
175
|
}
|
|
176
|
+
function shouldMatchAttachedMeshForGizmo() {
|
|
177
|
+
return space === 'local';
|
|
178
|
+
}
|
|
162
179
|
function applyHandlePreference() {
|
|
163
|
-
const positionGizmo = manager
|
|
180
|
+
const positionGizmo = manager?.gizmos?.positionGizmo;
|
|
164
181
|
if (positionGizmo) {
|
|
165
182
|
try {
|
|
166
183
|
positionGizmo.planarGizmoEnabled = tool === 'move';
|
|
@@ -169,26 +186,43 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
169
186
|
}
|
|
170
187
|
}
|
|
171
188
|
function attachCurrentSelection() {
|
|
189
|
+
clearDragObservers();
|
|
172
190
|
const activeTool = activeTransformTool();
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
191
|
+
if (!activeTool) {
|
|
192
|
+
if (manager) {
|
|
193
|
+
manager.positionGizmoEnabled = false;
|
|
194
|
+
manager.rotationGizmoEnabled = false;
|
|
195
|
+
manager.scaleGizmoEnabled = false;
|
|
196
|
+
try {
|
|
197
|
+
manager.attachToNode?.(null);
|
|
198
|
+
}
|
|
199
|
+
catch { }
|
|
200
|
+
}
|
|
201
|
+
updateFreeMoveHandle();
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const activeManager = ensureGizmoManager();
|
|
205
|
+
if (!activeManager) {
|
|
206
|
+
updateFreeMoveHandle();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
activeManager.positionGizmoEnabled = activeTool === 'move';
|
|
210
|
+
activeManager.rotationGizmoEnabled = activeTool === 'rotate';
|
|
211
|
+
activeManager.scaleGizmoEnabled = activeTool === 'scale';
|
|
176
212
|
applyHandlePreference();
|
|
177
213
|
applySpacePreference();
|
|
178
214
|
registerDragObservers();
|
|
179
215
|
let target = null;
|
|
180
|
-
|
|
181
|
-
target = attachNativeTransformProxy(getCurrentTransformTargetIds());
|
|
182
|
-
}
|
|
216
|
+
target = attachNativeTransformProxy(getCurrentTransformTargetIds());
|
|
183
217
|
try {
|
|
184
|
-
|
|
218
|
+
activeManager.attachToNode?.(target ?? null);
|
|
185
219
|
}
|
|
186
220
|
catch (error) {
|
|
187
221
|
options.logger?.warn?.('[BabylonTransformGizmoController] failed to attach gizmo', error);
|
|
188
222
|
}
|
|
189
223
|
updateFreeMoveHandle();
|
|
190
224
|
}
|
|
191
|
-
function beginDrag(activeConstraint = constraint) {
|
|
225
|
+
function beginDrag(activeConstraint = constraint, handleKey) {
|
|
192
226
|
if (activeDrag)
|
|
193
227
|
return;
|
|
194
228
|
const activeTool = activeTransformTool();
|
|
@@ -197,7 +231,7 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
197
231
|
const duplicate = pendingDuplicateDrag;
|
|
198
232
|
pendingDuplicateDrag = false;
|
|
199
233
|
const targetIds = resolveDragTargetIds(activeTool, getCurrentTransformTargetIds(), activeConstraint, duplicate);
|
|
200
|
-
const drag = createActiveDrag(activeTool, targetIds, activeConstraint, duplicate);
|
|
234
|
+
const drag = createActiveDrag(activeTool, targetIds, activeConstraint, duplicate, handleKey);
|
|
201
235
|
if (!drag)
|
|
202
236
|
return;
|
|
203
237
|
activeDrag = drag;
|
|
@@ -232,8 +266,11 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
232
266
|
const target = attachNativeTransformProxy(targetIds);
|
|
233
267
|
if (!target)
|
|
234
268
|
return false;
|
|
269
|
+
const activeManager = ensureGizmoManager();
|
|
270
|
+
if (!activeManager)
|
|
271
|
+
return false;
|
|
235
272
|
try {
|
|
236
|
-
|
|
273
|
+
activeManager.attachToNode?.(target);
|
|
237
274
|
updateFreeMoveHandle();
|
|
238
275
|
return true;
|
|
239
276
|
}
|
|
@@ -265,7 +302,7 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
265
302
|
}
|
|
266
303
|
: null;
|
|
267
304
|
}
|
|
268
|
-
function createActiveDrag(activeTool, targetIds, activeConstraint, duplicate = false) {
|
|
305
|
+
function createActiveDrag(activeTool, targetIds, activeConstraint, duplicate = false, handleKey) {
|
|
269
306
|
if (targetIds.length === 0)
|
|
270
307
|
return null;
|
|
271
308
|
const beforeTransforms = options.projection.readNodeTransforms(targetIds);
|
|
@@ -292,13 +329,19 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
292
329
|
before,
|
|
293
330
|
beforeTransforms,
|
|
294
331
|
duplicate,
|
|
332
|
+
handleKey,
|
|
295
333
|
proxyStart: readNativeProxyTransform(pivot),
|
|
296
334
|
};
|
|
297
335
|
}
|
|
298
336
|
function updateDrag() {
|
|
299
337
|
if (!activeDrag)
|
|
300
338
|
return;
|
|
301
|
-
const
|
|
339
|
+
const preview = previewBatchTransform(activeDrag);
|
|
340
|
+
if (!preview.ok) {
|
|
341
|
+
blockDrag(activeDrag, preview.reason, preview.failedTargetId);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
const currentTransforms = preview.transforms;
|
|
302
345
|
const current = activeDrag.activeId
|
|
303
346
|
? currentTransforms[activeDrag.activeId] ?? Object.values(currentTransforms)[0] ?? null
|
|
304
347
|
: Object.values(currentTransforms)[0] ?? null;
|
|
@@ -315,10 +358,32 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
315
358
|
const drag = activeDrag;
|
|
316
359
|
if (!drag)
|
|
317
360
|
return;
|
|
318
|
-
const
|
|
361
|
+
const preview = previewBatchTransform(drag);
|
|
362
|
+
if (!preview.ok) {
|
|
363
|
+
blockDrag(drag, preview.reason, preview.failedTargetId);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
activeDrag = null;
|
|
367
|
+
emitTransformCommit(drag, preview.transforms);
|
|
368
|
+
attachCurrentSelection();
|
|
369
|
+
}
|
|
370
|
+
function blockDrag(drag, reason, failedTargetId) {
|
|
319
371
|
activeDrag = null;
|
|
320
|
-
|
|
372
|
+
restoreDragPreview(drag);
|
|
321
373
|
attachCurrentSelection();
|
|
374
|
+
options.onDragBlocked?.({
|
|
375
|
+
...drag,
|
|
376
|
+
reason,
|
|
377
|
+
failedTargetId,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
function restoreDragPreview(drag) {
|
|
381
|
+
if (drag.targetIds.length > 1) {
|
|
382
|
+
options.projection.setNodeTransformsPreview(drag.beforeTransforms);
|
|
383
|
+
}
|
|
384
|
+
else if (drag.nodeId && drag.before) {
|
|
385
|
+
options.projection.setNodeTransformPreview(drag.nodeId, drag.before);
|
|
386
|
+
}
|
|
322
387
|
}
|
|
323
388
|
function emitTransformCommit(drag, afterTransforms) {
|
|
324
389
|
if (drag.targetIds.length === 1) {
|
|
@@ -367,15 +432,15 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
367
432
|
scale: { x: 1, y: 1, z: 1 },
|
|
368
433
|
};
|
|
369
434
|
if (drag.tool === 'move') {
|
|
370
|
-
return previewMoveWithDelta(drag, subtractVec3(pivotTransform.position, proxyStart.position));
|
|
435
|
+
return { ok: true, transforms: previewMoveWithDelta(drag, subtractVec3(pivotTransform.position, proxyStart.position)) };
|
|
371
436
|
}
|
|
372
437
|
if (drag.tool === 'rotate') {
|
|
373
|
-
return previewRotateWithDelta(drag,
|
|
438
|
+
return previewRotateWithDelta(drag, resolveRotationDelta(drag, pivotTransform, proxyStart));
|
|
374
439
|
}
|
|
375
440
|
if (drag.tool === 'scale') {
|
|
376
441
|
return previewScaleWithDelta(drag, divideVec3(pivotTransform.scale, proxyStart.scale));
|
|
377
442
|
}
|
|
378
|
-
return {};
|
|
443
|
+
return { ok: true, transforms: {} };
|
|
379
444
|
}
|
|
380
445
|
function previewMoveWithDelta(drag, delta) {
|
|
381
446
|
const transforms = {};
|
|
@@ -383,34 +448,54 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
383
448
|
const before = drag.beforeTransforms[nodeId];
|
|
384
449
|
if (!before)
|
|
385
450
|
continue;
|
|
386
|
-
|
|
451
|
+
const result = transformSolver.solveMove({ before, delta });
|
|
452
|
+
if (!result.ok)
|
|
453
|
+
continue;
|
|
454
|
+
transforms[nodeId] = applySnapToTransform(drag, nodeId, result.transform);
|
|
387
455
|
}
|
|
388
456
|
options.projection.setNodeTransformsPreview(transforms);
|
|
389
457
|
return transforms;
|
|
390
458
|
}
|
|
391
|
-
function translateTransform(transform, delta) {
|
|
392
|
-
return {
|
|
393
|
-
position: addVec3(transform.position, delta),
|
|
394
|
-
rotation: transform.rotation,
|
|
395
|
-
scale: transform.scale,
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
459
|
function previewRotateWithDelta(drag, rotationDelta) {
|
|
399
460
|
const transforms = {};
|
|
400
461
|
for (const nodeId of drag.targetIds) {
|
|
401
462
|
const before = drag.beforeTransforms[nodeId];
|
|
402
463
|
if (!before)
|
|
403
464
|
continue;
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
};
|
|
410
|
-
|
|
465
|
+
const result = transformSolver.solveRotate({
|
|
466
|
+
before,
|
|
467
|
+
pivot: drag.pivot.position,
|
|
468
|
+
delta: rotationDelta,
|
|
469
|
+
space: drag.space,
|
|
470
|
+
});
|
|
471
|
+
if (!result.ok) {
|
|
472
|
+
return { ok: false, reason: result.reason, failedTargetId: nodeId };
|
|
473
|
+
}
|
|
474
|
+
transforms[nodeId] = applySnapToTransform(drag, nodeId, result.transform);
|
|
411
475
|
}
|
|
412
476
|
options.projection.setNodeTransformsPreview(transforms);
|
|
413
|
-
return transforms;
|
|
477
|
+
return { ok: true, transforms };
|
|
478
|
+
}
|
|
479
|
+
function resolveRotationDelta(drag, pivotTransform, proxyStart) {
|
|
480
|
+
const angleDelta = readRotationHandleAngle(drag.handleKey);
|
|
481
|
+
if (angleDelta != null)
|
|
482
|
+
return rotationDeltaFromHandleAngle(drag.handleKey, angleDelta);
|
|
483
|
+
return subtractVec3(pivotTransform.rotation, proxyStart.rotation);
|
|
484
|
+
}
|
|
485
|
+
function readRotationHandleAngle(handleKey) {
|
|
486
|
+
if (handleKey !== 'xGizmo' && handleKey !== 'yGizmo' && handleKey !== 'zGizmo')
|
|
487
|
+
return null;
|
|
488
|
+
const angle = manager?.gizmos?.rotationGizmo?.[handleKey]?.angle;
|
|
489
|
+
return Number.isFinite(angle) ? Number(angle) : null;
|
|
490
|
+
}
|
|
491
|
+
function rotationDeltaFromHandleAngle(handleKey, angle) {
|
|
492
|
+
if (handleKey === 'xGizmo')
|
|
493
|
+
return { x: angle, y: 0, z: 0 };
|
|
494
|
+
if (handleKey === 'yGizmo')
|
|
495
|
+
return { x: 0, y: angle, z: 0 };
|
|
496
|
+
if (handleKey === 'zGizmo')
|
|
497
|
+
return { x: 0, y: 0, z: angle };
|
|
498
|
+
return { x: 0, y: 0, z: 0 };
|
|
414
499
|
}
|
|
415
500
|
function previewScaleWithDelta(drag, scaleDelta) {
|
|
416
501
|
const transforms = {};
|
|
@@ -423,16 +508,19 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
423
508
|
const before = drag.beforeTransforms[nodeId];
|
|
424
509
|
if (!before)
|
|
425
510
|
continue;
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
};
|
|
432
|
-
|
|
511
|
+
const result = transformSolver.solveScale({
|
|
512
|
+
before,
|
|
513
|
+
pivot: drag.pivot.position,
|
|
514
|
+
delta: safeScale,
|
|
515
|
+
space: drag.space,
|
|
516
|
+
});
|
|
517
|
+
if (!result.ok) {
|
|
518
|
+
return { ok: false, reason: result.reason, failedTargetId: nodeId };
|
|
519
|
+
}
|
|
520
|
+
transforms[nodeId] = applySnapToTransform(drag, nodeId, result.transform);
|
|
433
521
|
}
|
|
434
522
|
options.projection.setNodeTransformsPreview(transforms);
|
|
435
|
-
return transforms;
|
|
523
|
+
return { ok: true, transforms };
|
|
436
524
|
}
|
|
437
525
|
function applySnapToTransform(drag, nodeId, after) {
|
|
438
526
|
if (!operationSettings.snap.enabled)
|
|
@@ -490,13 +578,6 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
490
578
|
function dotVec3(left, right) {
|
|
491
579
|
return left.x * right.x + left.y * right.y + left.z * right.z;
|
|
492
580
|
}
|
|
493
|
-
function multiplyVec3(left, right) {
|
|
494
|
-
return {
|
|
495
|
-
x: left.x * right.x,
|
|
496
|
-
y: left.y * right.y,
|
|
497
|
-
z: left.z * right.z,
|
|
498
|
-
};
|
|
499
|
-
}
|
|
500
581
|
function divideVec3(left, right) {
|
|
501
582
|
return {
|
|
502
583
|
x: Math.abs(right.x) > 0.000001 ? left.x / right.x : 1,
|
|
@@ -504,36 +585,6 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
504
585
|
z: Math.abs(right.z) > 0.000001 ? left.z / right.z : 1,
|
|
505
586
|
};
|
|
506
587
|
}
|
|
507
|
-
function rotateVec3Euler(value, rotation) {
|
|
508
|
-
return rotateZ(rotateY(rotateX(value, rotation.x), rotation.y), rotation.z);
|
|
509
|
-
}
|
|
510
|
-
function rotateX(value, angle) {
|
|
511
|
-
const cos = Math.cos(angle);
|
|
512
|
-
const sin = Math.sin(angle);
|
|
513
|
-
return {
|
|
514
|
-
x: value.x,
|
|
515
|
-
y: value.y * cos - value.z * sin,
|
|
516
|
-
z: value.y * sin + value.z * cos,
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
function rotateY(value, angle) {
|
|
520
|
-
const cos = Math.cos(angle);
|
|
521
|
-
const sin = Math.sin(angle);
|
|
522
|
-
return {
|
|
523
|
-
x: value.x * cos + value.z * sin,
|
|
524
|
-
y: value.y,
|
|
525
|
-
z: -value.x * sin + value.z * cos,
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
function rotateZ(value, angle) {
|
|
529
|
-
const cos = Math.cos(angle);
|
|
530
|
-
const sin = Math.sin(angle);
|
|
531
|
-
return {
|
|
532
|
-
x: value.x * cos - value.y * sin,
|
|
533
|
-
y: value.x * sin + value.y * cos,
|
|
534
|
-
z: value.z,
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
588
|
function isViewPlaneMoveCandidate(event) {
|
|
538
589
|
if (disposed || activeDrag || tool !== 'move' || event.button !== 0)
|
|
539
590
|
return false;
|
|
@@ -720,7 +771,8 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
720
771
|
const MeshBuilder = options.babylon.MeshBuilder;
|
|
721
772
|
const StandardMaterial = options.babylon.StandardMaterial;
|
|
722
773
|
const Color3 = options.babylon.Color3;
|
|
723
|
-
const
|
|
774
|
+
const activeManager = ensureGizmoManager();
|
|
775
|
+
const utilityScene = activeManager?.utilityLayer?.utilityLayerScene;
|
|
724
776
|
if (!MeshBuilder?.CreateSphere || !utilityScene)
|
|
725
777
|
return null;
|
|
726
778
|
placementMarker = MeshBuilder.CreateSphere('editor.placement.marker', { diameter: 0.32, segments: 16 }, utilityScene);
|
|
@@ -767,7 +819,7 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
767
819
|
const rect = canvas.getBoundingClientRect();
|
|
768
820
|
const x = clientX - rect.left;
|
|
769
821
|
const y = clientY - rect.top;
|
|
770
|
-
const utilityScene = manager
|
|
822
|
+
const utilityScene = manager?.utilityLayer?.utilityLayerScene;
|
|
771
823
|
const utilityPick = typeof utilityScene?.pick === 'function' ? utilityScene.pick(x, y) : null;
|
|
772
824
|
if (utilityPick?.hit && utilityPick.pickedMesh)
|
|
773
825
|
return utilityPick.pickedMesh;
|
|
@@ -780,7 +832,7 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
780
832
|
const rect = canvas.getBoundingClientRect();
|
|
781
833
|
const x = clientX - rect.left;
|
|
782
834
|
const y = clientY - rect.top;
|
|
783
|
-
const utilityScene = manager
|
|
835
|
+
const utilityScene = manager?.utilityLayer?.utilityLayerScene;
|
|
784
836
|
const pick = typeof utilityScene?.pick === 'function'
|
|
785
837
|
? utilityScene.pick(x, y, (mesh) => isFreeMoveHandleNode(mesh))
|
|
786
838
|
: null;
|
|
@@ -792,7 +844,8 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
792
844
|
const MeshBuilder = options.babylon.MeshBuilder;
|
|
793
845
|
const StandardMaterial = options.babylon.StandardMaterial;
|
|
794
846
|
const Color3 = options.babylon.Color3;
|
|
795
|
-
const
|
|
847
|
+
const activeManager = ensureGizmoManager();
|
|
848
|
+
const utilityScene = activeManager?.utilityLayer?.utilityLayerScene;
|
|
796
849
|
if (!MeshBuilder?.CreateSphere || !utilityScene)
|
|
797
850
|
return null;
|
|
798
851
|
freeMoveHandle = MeshBuilder.CreateSphere('editor.transform.freeMoveHandle', { diameter: 0.22, segments: 12 }, utilityScene);
|
|
@@ -880,13 +933,16 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
880
933
|
}
|
|
881
934
|
function collectCurrentGizmoRoots() {
|
|
882
935
|
const roots = new Set();
|
|
936
|
+
const activeManager = manager;
|
|
937
|
+
if (!activeManager)
|
|
938
|
+
return roots;
|
|
883
939
|
const activeTool = activeTransformTool();
|
|
884
940
|
const gizmo = activeTool === 'move'
|
|
885
|
-
?
|
|
941
|
+
? activeManager.gizmos?.positionGizmo
|
|
886
942
|
: activeTool === 'rotate'
|
|
887
|
-
?
|
|
943
|
+
? activeManager.gizmos?.rotationGizmo
|
|
888
944
|
: activeTool === 'scale'
|
|
889
|
-
?
|
|
945
|
+
? activeManager.gizmos?.scaleGizmo
|
|
890
946
|
: null;
|
|
891
947
|
collectGizmoRoots(gizmo, roots);
|
|
892
948
|
return roots;
|
|
@@ -919,8 +975,11 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
919
975
|
setTool(nextTool) {
|
|
920
976
|
if (disposed)
|
|
921
977
|
return;
|
|
922
|
-
if (tool === nextTool)
|
|
978
|
+
if (tool === nextTool) {
|
|
979
|
+
if (!activeDrag)
|
|
980
|
+
attachCurrentSelection();
|
|
923
981
|
return;
|
|
982
|
+
}
|
|
924
983
|
controller.cancelDrag();
|
|
925
984
|
tool = nextTool;
|
|
926
985
|
constraint = normalizeConstraintForTool(tool, constraint) ?? 'axis';
|
|
@@ -929,8 +988,11 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
929
988
|
setSpace(nextSpace) {
|
|
930
989
|
if (disposed)
|
|
931
990
|
return;
|
|
932
|
-
if (space === nextSpace)
|
|
991
|
+
if (space === nextSpace) {
|
|
992
|
+
if (!activeDrag)
|
|
993
|
+
attachCurrentSelection();
|
|
933
994
|
return;
|
|
995
|
+
}
|
|
934
996
|
controller.cancelDrag();
|
|
935
997
|
space = nextSpace;
|
|
936
998
|
attachCurrentSelection();
|
|
@@ -939,8 +1001,11 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
939
1001
|
if (disposed)
|
|
940
1002
|
return;
|
|
941
1003
|
const normalized = normalizeConstraintForTool(tool, nextConstraint) ?? 'axis';
|
|
942
|
-
if (constraint === normalized)
|
|
1004
|
+
if (constraint === normalized) {
|
|
1005
|
+
if (!activeDrag)
|
|
1006
|
+
attachCurrentSelection();
|
|
943
1007
|
return;
|
|
1008
|
+
}
|
|
944
1009
|
controller.cancelDrag();
|
|
945
1010
|
constraint = normalized;
|
|
946
1011
|
attachCurrentSelection();
|
|
@@ -1016,11 +1081,11 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
1016
1081
|
controller.cancelDrag();
|
|
1017
1082
|
clearDragObservers();
|
|
1018
1083
|
try {
|
|
1019
|
-
manager
|
|
1084
|
+
manager?.attachToNode?.(null);
|
|
1020
1085
|
}
|
|
1021
1086
|
catch { }
|
|
1022
1087
|
try {
|
|
1023
|
-
manager
|
|
1088
|
+
manager?.dispose?.();
|
|
1024
1089
|
}
|
|
1025
1090
|
catch { }
|
|
1026
1091
|
try {
|
|
@@ -1048,6 +1113,7 @@ export function createBabylonTransformGizmoController(options) {
|
|
|
1048
1113
|
freeMoveHandleMaterial = null;
|
|
1049
1114
|
placementMarker = null;
|
|
1050
1115
|
placementMarkerMaterial = null;
|
|
1116
|
+
manager = null;
|
|
1051
1117
|
disposed = true;
|
|
1052
1118
|
},
|
|
1053
1119
|
};
|