@tomorrowevening/hermes 0.0.11 → 0.0.13
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/hermes.js +1541 -1446
- package/dist/hermes.umd.cjs +16 -16
- package/dist/style.css +1 -1
- package/package.json +3 -2
- package/src/core/Application.ts +1 -1
- package/src/core/RemoteController.ts +4 -151
- package/src/core/remote/RemoteComponents.ts +15 -1
- package/src/core/remote/RemoteTheatre.ts +114 -3
- package/src/core/remote/RemoteThree.ts +57 -2
- package/src/core/remote/RemoteTweakpane.ts +28 -2
- package/src/core/types.ts +2 -0
- package/src/editor/global.ts +3 -0
- package/src/editor/multiView/CameraWindow.tsx +20 -7
- package/src/editor/multiView/MultiView.scss +2 -0
- package/src/editor/multiView/MultiView.tsx +203 -9
- package/src/editor/scss/{_sceneHierarchy.scss → _sidePanel.scss} +1 -1
- package/src/editor/scss/index.scss +1 -1
- package/src/editor/{sceneHierarchy/SceneHierarchy.tsx → sidePanel/SidePanel.tsx} +8 -10
- package/src/editor/sidePanel/inspector/Inspector.tsx +111 -0
- package/src/editor/sidePanel/inspector/utils/InspectAnimation.tsx +51 -0
- package/src/editor/{sceneHierarchy → sidePanel}/types.ts +10 -1
- package/src/editor/{sceneHierarchy → sidePanel}/utils.ts +11 -2
- package/src/index.ts +6 -6
- package/types/core/Application.d.ts +1 -1
- package/types/core/RemoteController.d.ts +1 -1
- package/types/core/remote/RemoteComponents.d.ts +3 -0
- package/types/core/remote/RemoteTheatre.d.ts +3 -0
- package/types/core/remote/RemoteThree.d.ts +7 -1
- package/types/core/remote/RemoteTweakpane.d.ts +2 -0
- package/types/core/types.d.ts +1 -1
- package/types/editor/global.d.ts +2 -0
- package/types/editor/multiView/CameraWindow.d.ts +2 -0
- package/types/editor/multiView/MultiView.d.ts +4 -0
- package/types/editor/sidePanel/SidePanel.d.ts +11 -0
- package/types/editor/sidePanel/inspector/utils/InspectAnimation.d.ts +3 -0
- package/types/editor/{sceneHierarchy → sidePanel}/types.d.ts +7 -1
- package/types/index.d.ts +6 -6
- package/src/editor/sceneHierarchy/inspector/Inspector.tsx +0 -97
- package/types/editor/sceneHierarchy/SceneHierarchy.d.ts +0 -11
- /package/src/editor/{sceneHierarchy → sidePanel}/Accordion.tsx +0 -0
- /package/src/editor/{sceneHierarchy → sidePanel}/ChildObject.tsx +0 -0
- /package/src/editor/{sceneHierarchy → sidePanel}/ContainerObject.tsx +0 -0
- /package/src/editor/{sceneHierarchy → sidePanel}/ToggleBtn.tsx +0 -0
- /package/src/editor/{sceneHierarchy → sidePanel}/inspector/InspectorField.tsx +0 -0
- /package/src/editor/{sceneHierarchy → sidePanel}/inspector/InspectorGroup.tsx +0 -0
- /package/src/editor/{sceneHierarchy → sidePanel}/inspector/SceneInspector.tsx +0 -0
- /package/src/editor/{sceneHierarchy → sidePanel}/inspector/inspector.scss +0 -0
- /package/src/editor/{sceneHierarchy → sidePanel}/inspector/utils/InspectCamera.tsx +0 -0
- /package/src/editor/{sceneHierarchy → sidePanel}/inspector/utils/InspectLight.tsx +0 -0
- /package/src/editor/{sceneHierarchy → sidePanel}/inspector/utils/InspectMaterial.tsx +0 -0
- /package/src/editor/{sceneHierarchy → sidePanel}/inspector/utils/InspectTransform.tsx +0 -0
- /package/types/editor/{sceneHierarchy → sidePanel}/Accordion.d.ts +0 -0
- /package/types/editor/{sceneHierarchy → sidePanel}/ChildObject.d.ts +0 -0
- /package/types/editor/{sceneHierarchy → sidePanel}/ContainerObject.d.ts +0 -0
- /package/types/editor/{sceneHierarchy → sidePanel}/ToggleBtn.d.ts +0 -0
- /package/types/editor/{sceneHierarchy → sidePanel}/inspector/Inspector.d.ts +0 -0
- /package/types/editor/{sceneHierarchy → sidePanel}/inspector/InspectorField.d.ts +0 -0
- /package/types/editor/{sceneHierarchy → sidePanel}/inspector/InspectorGroup.d.ts +0 -0
- /package/types/editor/{sceneHierarchy → sidePanel}/inspector/SceneInspector.d.ts +0 -0
- /package/types/editor/{sceneHierarchy → sidePanel}/inspector/utils/InspectCamera.d.ts +0 -0
- /package/types/editor/{sceneHierarchy → sidePanel}/inspector/utils/InspectLight.d.ts +0 -0
- /package/types/editor/{sceneHierarchy → sidePanel}/inspector/utils/InspectMaterial.d.ts +0 -0
- /package/types/editor/{sceneHierarchy → sidePanel}/inspector/utils/InspectTransform.d.ts +0 -0
- /package/types/editor/{sceneHierarchy → sidePanel}/utils.d.ts +0 -0
package/src/core/types.ts
CHANGED
package/src/editor/global.ts
CHANGED
@@ -14,4 +14,7 @@ export const ToolEvents = {
|
|
14
14
|
UPDATE_OBJECT: 'ToolEvents::updateObject',
|
15
15
|
CREATE_TEXTURE: 'ToolEvents::createTexture',
|
16
16
|
REQUEST_METHOD: 'ToolEvents::requestMethod',
|
17
|
+
// MultiView
|
18
|
+
ADD_CAMERA: 'ToolEvents::addCamera',
|
19
|
+
REMOVE_CAMERA: 'ToolEvents::removeCamera',
|
17
20
|
};
|
@@ -2,18 +2,19 @@ import { ForwardedRef, forwardRef, useState } from 'react';
|
|
2
2
|
import { Camera } from 'three';
|
3
3
|
|
4
4
|
interface DropdownProps {
|
5
|
-
index: number
|
5
|
+
index: number;
|
6
|
+
open: boolean;
|
7
|
+
onToggle: (value: boolean) => void;
|
6
8
|
onSelect: (value: string) => void;
|
7
9
|
options: string[];
|
8
10
|
up?: boolean;
|
9
11
|
}
|
10
12
|
|
11
13
|
export const Dropdown = (props: DropdownProps) => {
|
12
|
-
const [isOpen, setIsOpen] = useState(false);
|
13
14
|
const [selectedOption, setSelectedOption] = useState(props.options[props.index]);
|
14
15
|
|
15
16
|
const handleToggle = () => {
|
16
|
-
|
17
|
+
props.onToggle(!props.open);
|
17
18
|
};
|
18
19
|
|
19
20
|
const handleSelect = (option: any) => {
|
@@ -21,7 +22,7 @@ export const Dropdown = (props: DropdownProps) => {
|
|
21
22
|
props.onSelect(option);
|
22
23
|
setSelectedOption(option);
|
23
24
|
}
|
24
|
-
|
25
|
+
props.onToggle(false);
|
25
26
|
};
|
26
27
|
|
27
28
|
return (
|
@@ -29,7 +30,7 @@ export const Dropdown = (props: DropdownProps) => {
|
|
29
30
|
<div className="dropdown-toggle" onClick={handleToggle}>
|
30
31
|
{selectedOption}
|
31
32
|
</div>
|
32
|
-
{
|
33
|
+
{props.open && (
|
33
34
|
<ul className="dropdown-menu">
|
34
35
|
{props.options.map((option) => (
|
35
36
|
<li key={option} onClick={() => handleSelect(option)}>
|
@@ -49,11 +50,23 @@ interface CameraWindowProps {
|
|
49
50
|
}
|
50
51
|
|
51
52
|
const CameraWindow = forwardRef(function CameraWindow(props: CameraWindowProps, ref: ForwardedRef<HTMLDivElement>) {
|
53
|
+
const [open, setOpen] = useState(false);
|
52
54
|
const index = props.options.indexOf(props.camera.name);
|
53
55
|
return (
|
54
56
|
<div className='CameraWindow'>
|
55
|
-
<div ref={ref} className='clickable'
|
56
|
-
|
57
|
+
<div ref={ref} className='clickable' onClick={() => {
|
58
|
+
if (open) setOpen(false);
|
59
|
+
}} />
|
60
|
+
<Dropdown
|
61
|
+
index={index}
|
62
|
+
open={open}
|
63
|
+
options={props.options}
|
64
|
+
onSelect={props.onSelect}
|
65
|
+
onToggle={(value: boolean) => {
|
66
|
+
setOpen(value);
|
67
|
+
}}
|
68
|
+
up={true}
|
69
|
+
/>
|
57
70
|
</div>
|
58
71
|
);
|
59
72
|
});
|
@@ -54,6 +54,7 @@ $padding: 2px;
|
|
54
54
|
.cameras {
|
55
55
|
display: grid;
|
56
56
|
grid-template-columns: repeat(2, 1fr);
|
57
|
+
pointer-events: visible;
|
57
58
|
position: absolute;
|
58
59
|
width: 100%;
|
59
60
|
height: 100%;
|
@@ -92,6 +93,7 @@ $padding: 2px;
|
|
92
93
|
}
|
93
94
|
|
94
95
|
.settings {
|
96
|
+
pointer-events: visible;
|
95
97
|
position: absolute;
|
96
98
|
left: 50%;
|
97
99
|
transform: translateX(-50%);
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import { useEffect, useRef, useState } from 'react';
|
2
|
-
import { AxesHelper, Camera, CameraHelper, OrthographicCamera, PerspectiveCamera, Scene, WebGLRenderer } from 'three';
|
2
|
+
import { AxesHelper, Camera, CameraHelper, Group, OrthographicCamera, PerspectiveCamera, Raycaster, Scene, Vector2, WebGLRenderer } from 'three';
|
3
3
|
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
|
4
4
|
import CameraWindow, { Dropdown } from './CameraWindow';
|
5
5
|
import InfiniteGridHelper from './InfiniteGridHelper';
|
@@ -8,6 +8,7 @@ import './MultiView.scss';
|
|
8
8
|
import RemoteThree from '@/core/remote/RemoteThree';
|
9
9
|
import { ToolEvents, debugDispatcher } from '../global';
|
10
10
|
import { dispose } from '../utils';
|
11
|
+
import { mapLinear } from 'three/src/math/MathUtils';
|
11
12
|
|
12
13
|
let currentRenderMode: RenderMode = 'Renderer';
|
13
14
|
|
@@ -19,12 +20,23 @@ scene.name = 'Debug Scene';
|
|
19
20
|
let currentScene = new Scene();
|
20
21
|
scene.add(currentScene);
|
21
22
|
|
23
|
+
const helpersContainer = new Group();
|
24
|
+
helpersContainer.name = 'helpers';
|
25
|
+
scene.add(helpersContainer);
|
26
|
+
|
22
27
|
const grid = new InfiniteGridHelper();
|
23
|
-
|
28
|
+
helpersContainer.add(grid);
|
24
29
|
|
25
30
|
const axisHelper = new AxesHelper(500);
|
26
31
|
axisHelper.name = 'axisHelper';
|
27
|
-
|
32
|
+
helpersContainer.add(axisHelper);
|
33
|
+
|
34
|
+
const interactionHelper = new AxesHelper(100);
|
35
|
+
interactionHelper.name = 'interactionHelper';
|
36
|
+
helpersContainer.add(interactionHelper);
|
37
|
+
interactionHelper.visible = false;
|
38
|
+
|
39
|
+
let useRaycaster = false;
|
28
40
|
|
29
41
|
// Cameras
|
30
42
|
|
@@ -32,20 +44,28 @@ let tlCam = cameras.get('Debug')!;
|
|
32
44
|
let trCam = cameras.get('Orthographic')!;
|
33
45
|
let blCam = cameras.get('Front')!;
|
34
46
|
let brCam = cameras.get('Top')!;
|
47
|
+
let sceneSet = false;
|
35
48
|
|
36
49
|
interface MultiViewProps {
|
37
50
|
three: RemoteThree;
|
38
51
|
mode?: MultiViewMode;
|
52
|
+
scenes: Map<string, any>;
|
53
|
+
onSceneSet?: (scene: Scene) => void;
|
54
|
+
onSceneUpdate?: (scene: Scene) => void;
|
39
55
|
}
|
40
56
|
|
41
57
|
export default function MultiView(props: MultiViewProps) {
|
42
58
|
// States
|
43
|
-
const [mode, setMode] = useState<MultiViewMode>(props.mode !== undefined ? props.mode : '
|
59
|
+
const [mode, setMode] = useState<MultiViewMode>(props.mode !== undefined ? props.mode : 'Single');
|
44
60
|
const [renderer, setRenderer] = useState<WebGLRenderer | null>(null);
|
61
|
+
const [modeOpen, setModeOpen] = useState(false);
|
62
|
+
const [renderModeOpen, setRenderModeOpen] = useState(false);
|
63
|
+
const [interactionModeOpen, setInteractionModeOpen] = useState(false);
|
64
|
+
const [, setLastUpdate] = useState(Date.now());
|
45
65
|
|
46
66
|
// References
|
47
67
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
48
|
-
|
68
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
49
69
|
const tlWindow = useRef<HTMLDivElement>(null);
|
50
70
|
const trWindow = useRef<HTMLDivElement>(null);
|
51
71
|
const blWindow = useRef<HTMLDivElement>(null);
|
@@ -150,17 +170,40 @@ export default function MultiView(props: MultiViewProps) {
|
|
150
170
|
|
151
171
|
// Event handling
|
152
172
|
useEffect(() => {
|
153
|
-
const sceneUpdate = () => {
|
173
|
+
const sceneUpdate = (evt: any) => {
|
154
174
|
dispose(currentScene);
|
155
175
|
scene.remove(currentScene);
|
156
|
-
|
157
|
-
|
176
|
+
|
177
|
+
const sceneClass = props.scenes.get(evt.value.name);
|
178
|
+
if (sceneClass !== undefined) {
|
179
|
+
const sceneInstance = new sceneClass();
|
180
|
+
if (props.onSceneSet !== undefined) props.onSceneSet(sceneInstance);
|
181
|
+
currentScene = sceneInstance;
|
182
|
+
props.three.scene = currentScene;
|
158
183
|
scene.add(currentScene);
|
184
|
+
sceneSet = true;
|
159
185
|
}
|
160
186
|
};
|
187
|
+
|
188
|
+
const addCamera = (evt: any) => {
|
189
|
+
const data = evt.value;
|
190
|
+
const child = props.three.scene?.getObjectByProperty('uuid', data.uuid);
|
191
|
+
if (child !== undefined) cameras.set(data.name, child as Camera);
|
192
|
+
setLastUpdate(Date.now());
|
193
|
+
};
|
194
|
+
|
195
|
+
const removeCamera = (evt: any) => {
|
196
|
+
cameras.delete(evt.value.name);
|
197
|
+
setLastUpdate(Date.now());
|
198
|
+
};
|
199
|
+
|
161
200
|
debugDispatcher.addEventListener(ToolEvents.SET_SCENE, sceneUpdate);
|
201
|
+
debugDispatcher.addEventListener(ToolEvents.ADD_CAMERA, addCamera);
|
202
|
+
debugDispatcher.addEventListener(ToolEvents.REMOVE_CAMERA, removeCamera);
|
162
203
|
return () => {
|
163
204
|
debugDispatcher.removeEventListener(ToolEvents.SET_SCENE, sceneUpdate);
|
205
|
+
debugDispatcher.removeEventListener(ToolEvents.ADD_CAMERA, addCamera);
|
206
|
+
debugDispatcher.removeEventListener(ToolEvents.REMOVE_CAMERA, removeCamera);
|
164
207
|
};
|
165
208
|
}, []);
|
166
209
|
|
@@ -277,6 +320,8 @@ export default function MultiView(props: MultiViewProps) {
|
|
277
320
|
control.update();
|
278
321
|
});
|
279
322
|
|
323
|
+
if (props.onSceneUpdate !== undefined && sceneSet) props.onSceneUpdate(currentScene);
|
324
|
+
|
280
325
|
// Drawing
|
281
326
|
renderer.clear();
|
282
327
|
switch (mode) {
|
@@ -308,6 +353,123 @@ export default function MultiView(props: MultiViewProps) {
|
|
308
353
|
};
|
309
354
|
}, [mode, renderer]);
|
310
355
|
|
356
|
+
// Raycaster
|
357
|
+
useEffect(() => {
|
358
|
+
if (renderer !== null) {
|
359
|
+
const raycaster = new Raycaster();
|
360
|
+
const pointer = new Vector2();
|
361
|
+
|
362
|
+
const updateCamera = (mouseX: number, mouseY: number, hw: number, hh: number) => {
|
363
|
+
switch (mode) {
|
364
|
+
case 'Quad':
|
365
|
+
if (mouseX < hw) {
|
366
|
+
if (mouseY < hh) {
|
367
|
+
raycaster.setFromCamera(pointer, tlCam);
|
368
|
+
} else {
|
369
|
+
raycaster.setFromCamera(pointer, blCam);
|
370
|
+
}
|
371
|
+
} else {
|
372
|
+
if (mouseY < hh) {
|
373
|
+
raycaster.setFromCamera(pointer, trCam);
|
374
|
+
} else {
|
375
|
+
raycaster.setFromCamera(pointer, brCam);
|
376
|
+
}
|
377
|
+
}
|
378
|
+
break;
|
379
|
+
case 'Side by Side':
|
380
|
+
if (mouseX < hw) {
|
381
|
+
raycaster.setFromCamera(pointer, tlCam);
|
382
|
+
} else {
|
383
|
+
raycaster.setFromCamera(pointer, trCam);
|
384
|
+
}
|
385
|
+
break;
|
386
|
+
case 'Single':
|
387
|
+
raycaster.setFromCamera(pointer, tlCam);
|
388
|
+
break;
|
389
|
+
case 'Stacked':
|
390
|
+
if (mouseY < hh) {
|
391
|
+
raycaster.setFromCamera(pointer, tlCam);
|
392
|
+
} else {
|
393
|
+
raycaster.setFromCamera(pointer, trCam);
|
394
|
+
}
|
395
|
+
break;
|
396
|
+
}
|
397
|
+
};
|
398
|
+
|
399
|
+
const onMouseMove = (event: MouseEvent) => {
|
400
|
+
if (!useRaycaster) return;
|
401
|
+
const size = new Vector2();
|
402
|
+
renderer!.getSize(size);
|
403
|
+
|
404
|
+
const mouseX = Math.min(event.clientX, size.x);
|
405
|
+
const mouseY = Math.min(event.clientY, size.y);
|
406
|
+
pointer.x = mapLinear(mouseX, 0, size.x, -1, 1);
|
407
|
+
pointer.y = mapLinear(mouseY, 0, size.y, 1, -1);
|
408
|
+
|
409
|
+
const hw = size.x / 2;
|
410
|
+
const hh = size.y / 2;
|
411
|
+
|
412
|
+
const sideBySide = () => {
|
413
|
+
if (mouseX < hw) {
|
414
|
+
pointer.x = mapLinear(mouseX, 0, hw, -1, 1);
|
415
|
+
} else {
|
416
|
+
pointer.x = mapLinear(mouseX, hw, size.x, -1, 1);
|
417
|
+
}
|
418
|
+
};
|
419
|
+
|
420
|
+
const stacked = () => {
|
421
|
+
if (mouseY < hh) {
|
422
|
+
pointer.y = mapLinear(mouseY, 0, hh, 1, -1);
|
423
|
+
} else {
|
424
|
+
pointer.y = mapLinear(mouseY, hh, size.y, 1, -1);
|
425
|
+
}
|
426
|
+
};
|
427
|
+
|
428
|
+
// mapLinear
|
429
|
+
switch (mode) {
|
430
|
+
case 'Quad':
|
431
|
+
sideBySide();
|
432
|
+
stacked();
|
433
|
+
break;
|
434
|
+
case 'Side by Side':
|
435
|
+
sideBySide();
|
436
|
+
break;
|
437
|
+
case 'Stacked':
|
438
|
+
stacked();
|
439
|
+
stacked();
|
440
|
+
break;
|
441
|
+
}
|
442
|
+
|
443
|
+
updateCamera(mouseX, mouseY, hw, hh);
|
444
|
+
const intersects = raycaster.intersectObjects(currentScene.children);
|
445
|
+
if (intersects.length > 0) interactionHelper.position.copy(intersects[0].point);
|
446
|
+
};
|
447
|
+
|
448
|
+
const onClick = (event: MouseEvent) => {
|
449
|
+
if (!useRaycaster) return;
|
450
|
+
|
451
|
+
const size = new Vector2();
|
452
|
+
renderer!.getSize(size);
|
453
|
+
if (event.clientX >= size.x) return;
|
454
|
+
|
455
|
+
onMouseMove(event);
|
456
|
+
|
457
|
+
const intersects = raycaster.intersectObjects(currentScene.children);
|
458
|
+
if (intersects.length > 0) {
|
459
|
+
props.three.getObject(intersects[0].object.uuid);
|
460
|
+
}
|
461
|
+
};
|
462
|
+
|
463
|
+
const element = containerRef.current!;
|
464
|
+
element.addEventListener('mousemove', onMouseMove, false);
|
465
|
+
element.addEventListener('click', onClick, false);
|
466
|
+
return () => {
|
467
|
+
element.removeEventListener('mousemove', onMouseMove);
|
468
|
+
element.removeEventListener('click', onClick);
|
469
|
+
};
|
470
|
+
}
|
471
|
+
}, [mode, renderer]);
|
472
|
+
|
311
473
|
// Camera names
|
312
474
|
const cameraOptions: string[] = [];
|
313
475
|
cameras.forEach((_: Camera, key: string) => {
|
@@ -318,7 +480,7 @@ export default function MultiView(props: MultiViewProps) {
|
|
318
480
|
<div className='multiview'>
|
319
481
|
<canvas ref={canvasRef} />
|
320
482
|
|
321
|
-
<div className={`cameras ${mode === 'Single' || mode === 'Stacked' ? 'single' : ''}`}>
|
483
|
+
<div className={`cameras ${mode === 'Single' || mode === 'Stacked' ? 'single' : ''}`} ref={containerRef}>
|
322
484
|
{mode === 'Single' && (
|
323
485
|
<>
|
324
486
|
<CameraWindow camera={tlCam} options={cameraOptions} ref={tlWindow} onSelect={(value: string) => {
|
@@ -408,7 +570,14 @@ export default function MultiView(props: MultiViewProps) {
|
|
408
570
|
killControls();
|
409
571
|
setMode(value as MultiViewMode);
|
410
572
|
}}
|
573
|
+
open={modeOpen}
|
574
|
+
onToggle={(value: boolean) => {
|
575
|
+
setModeOpen(value);
|
576
|
+
if (renderModeOpen) setRenderModeOpen(false);
|
577
|
+
if (interactionModeOpen) setInteractionModeOpen(false);
|
578
|
+
}}
|
411
579
|
/>
|
580
|
+
|
412
581
|
{/* Render Mode */}
|
413
582
|
<Dropdown
|
414
583
|
index={renderOptions.indexOf(currentRenderMode)}
|
@@ -435,6 +604,31 @@ export default function MultiView(props: MultiViewProps) {
|
|
435
604
|
break;
|
436
605
|
}
|
437
606
|
}}
|
607
|
+
open={renderModeOpen}
|
608
|
+
onToggle={(value: boolean) => {
|
609
|
+
if (modeOpen) setModeOpen(false);
|
610
|
+
setRenderModeOpen(value);
|
611
|
+
if (interactionModeOpen) setInteractionModeOpen(false);
|
612
|
+
}}
|
613
|
+
/>
|
614
|
+
|
615
|
+
{/* Interaction Mode */}
|
616
|
+
<Dropdown
|
617
|
+
index={0}
|
618
|
+
options={[
|
619
|
+
'Orbit Mode',
|
620
|
+
'Selection Mode',
|
621
|
+
]}
|
622
|
+
onSelect={(value: string) => {
|
623
|
+
useRaycaster = value === 'Selection Mode';
|
624
|
+
interactionHelper.visible = useRaycaster;
|
625
|
+
}}
|
626
|
+
open={interactionModeOpen}
|
627
|
+
onToggle={(value: boolean) => {
|
628
|
+
if (modeOpen) setModeOpen(false);
|
629
|
+
if (renderModeOpen) setRenderModeOpen(false);
|
630
|
+
setInteractionModeOpen(value);
|
631
|
+
}}
|
438
632
|
/>
|
439
633
|
</div>
|
440
634
|
</div>
|
@@ -9,7 +9,7 @@ $icon_ui: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rh
|
|
9
9
|
$icon_utils: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAACXBIWXMAAAsTAAALEwEAmpwYAAADFElEQVRYhe2YT0hVQRSHf7YwsUVoakFtKmhdUfhUeLSrrFVQEES72rip1EoscFlLK2jRpl21tT8QhFkLq13gIotqlaRPQ8SkgvRrcefiOO/eufN8LzPwwMV375w5893fnHPm+aoArWZb968BsmwNsFz7rwHzkgYltVdgnRpJZyU9lTQm6ZukUUl9GQwSkHS1AgUimwduAHUpvlnXLmCYYpsFDmXNT3p4AJhICDgC7C0RbgvwISHWGNASEiPpYdLbxvYJ2FQC4F1rbj/w1nx+ERoj6WE78NsDeSIw+E7gh5kzYJ5dM/dzwFbH/yDQ58ZJStAnkm570rY+sDDaTHEgqd88GzJ/ayWdk7Td3Ock3Zd0OrRINgKjKQq+ApoCFOw0/j8tteqAaSvWd6LtjgtyKkRBSZqRdFLS+4SxnKQBSU0ZCsaHfLXlOy3plqRxc79BUTtrNPe/QhWU9cbHgQ7gTYKSm1Pm5YAvlm+bM15PlOvXWSwcgGdurFJaRpOBsu010Oj4tVhbBtAFVHni3rR8z5QDKKNYEmSsZI6lPbTbmZ8HdgPbgMNE1R3bMFBbLqCABgNl20vgmAN30ZnXRXQqzbPYfmIbAXYkrbccwLTtts1VrjvFbxa4Q3GalA0Yb/fzALgua2zcjHcDp0hRrVKAAo4CCx64XmtsksDzt1KAbitx4a5YY1+BPctZZ7lwzfgLwlZuxQFb8LcSW7k5FlNgRbY4R5ToIXATREp3OM9a/xZgjqUnhG9bZ4D91linNTZpYlUU0IVzlbMBIGrE5z0+hVAlQ3POt63uwnZ+XvL4ThCQk5VUbhLYR1StNmSPM+eCM8erZBacr1rtE8JVw21Dlz0vVsCTk2lwDcBnE2CB4oKwz9YCyVvltqOkLw9xC/pIyj9jaYBHrMC9Hris3pYzPmmQPdZYeymAeWviPaAmAS4oyT1KrjexY8uXAlgNPLImP2BpnwtuExakXWxXHbjHZs2SiqQeGKTYpgKVy9ru2IbMWiVXcQxpfy1/t0y4+Go2MWJ7SMYvFVWw9hNwWbYGWK6tesA/ap/6uHJWeiAAAAAASUVORK5CYII=');
|
10
10
|
$icon_world: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEZklEQVRYhe2YW4iVVRTHf4465oSaUNlUjo7SmCBEPVipTWYXoV7qoejykhRCEVQP9pAFSWVBPdRTMNRLWGRaFr2FSShmEQ1KzQymUhpeMky6ONbcfj3sdZpvvvnO8Zy5lA/+YcP51jpr7bVv/7X2nqByNqPu/w7gTDgX4GgxaYR2DcDlwC3AUmAh0ARMDf1fwGGgE9gFfAb8AJyquSe1ljZFXa6+o/Y4FD3qvmh5neomdYXaUEuftQQ3T31d7Y8O96tdal98P69eos5SXwhZn7pb7cgE2qa2jHWAy9Svo4Nf1VfUG9VPQvauWp/5f726MXSb1WvVF9XjIftWvXWsArxdPRSOt5uWCfV+dUDtVJsL7K5Q98aM3xuyVnVr+Dqi3jHaAJepx8Lhe2pTyJvVn6PzVRXsHw7bw+rckDWqb4b8mHrbSAOcp7aHozZ1Wka3NuQfqHUVfExUt8R/n8rI69XXQt6lLijnoxzNTAEeA64GeoDzgbVBI5OBu+J/FwPrg3aK0A1cGL8fB+YAfUFDF4T+SmAN8ATwZ97BBC3MxdeTuGtqOBSYkGklgu/NyIpgtMnxPRDfpd9kdCuBT/MOimawHlgdwW0DPs918AAwH9gK7MjoyqEHWA6sAPYBGzMD6gWWRHCPhL/TQ4dYfPpOxSFYXKDvVE+YaKZamrpZPWmil7xuoXrQxAiL8vqiXHwTaU99BbTndItJe+Zoga4S2oFjpJR4TU7XBXwZs7oyb1gU4DKgH/iCtP+yaAlH+4E/agjwJCkXTwwfeewgLXdrNQEuAn6neIYaSfvwQA3BlXCAdEAaC3TtpEFclVcUHZIm0sauC2f1Ie8lLZGkmbiI8vSSR3fYDYSPyzJ990YfvQxS0r8oopkTJI76jbTUpRMnMI3Ekd2k0qnaenKAxKUNwN+k7ZH1Wxd9nswHWWvBWo7vxg1FSyzwC/AgsIfBJe4DngNWAW1UziB5dAPPAo8CbwPrGLrELcAGYEY1AR4C5pKW5WhOt5c0iwMxiFpQykBdpGo7i7kkwj+eNypa4g5gOsP5ChKX1ZG4sFbMjyDzgyb6mgl8V02AO0mndAnDZ/h70hZoJg2iWswMm37SKuRxA2kGtw/TFKSelipTXesIUt3uWlNd0R78EXifdEheYnixMDlm5BlqKxZmkChqHcOLhdnAxxQkgErl1jbgPM7CcgtS6nkDeDIcbQZ+IpVgk4A7gUtJBcVOKhesS0n5/QjwEYMF6yzg7gjwLVLuLxhi+X3TrH4TZXmbOj2jezrkZyr5JzlY8q/JyKsu+UdzaToaG/uhCvarw/agOscxvjSVWvbaucPBa+d9plvdXlORm7dbELo+9Z6Qjfm1MzuT2Yv7q9HZlpBtdOjFfar6Yeg2qdep6x2ni3upFT19dDj49PGy6emjMQZg6PaY9lkJ4/L0UWqlx6MNDn8g6o2g98fvPEb0eFSOB8+Eoue32Rm6OR200hn0sY0RPr+NNMD/DGf9C+u5AEeLfwBkrdN1844nCgAAAABJRU5ErkJggg==');
|
11
11
|
|
12
|
-
#
|
12
|
+
#SidePanel {
|
13
13
|
background-color: #0d0d0d;
|
14
14
|
border: 1px solid #111;
|
15
15
|
max-height: 100%;
|
@@ -3,17 +3,17 @@ import { Component, ReactNode } from 'react';
|
|
3
3
|
// Models
|
4
4
|
import { debugDispatcher, ToolEvents } from '../global';
|
5
5
|
// Components
|
6
|
-
import '../scss/
|
6
|
+
import '../scss/_sidePanel.scss';
|
7
7
|
import Accordion from './Accordion';
|
8
8
|
import ContainerObject from './ContainerObject';
|
9
9
|
import Inspector from './inspector/Inspector';
|
10
|
-
import {
|
10
|
+
import { SidePanelState } from './types';
|
11
11
|
import RemoteThree from '@/core/remote/RemoteThree';
|
12
12
|
|
13
|
-
export default class
|
13
|
+
export default class SidePanel extends Component<SidePanelState> {
|
14
14
|
private three: RemoteThree;
|
15
15
|
|
16
|
-
constructor(props:
|
16
|
+
constructor(props: SidePanelState) {
|
17
17
|
super(props);
|
18
18
|
this.state = {
|
19
19
|
scene: props.scene !== undefined ? props.scene : null,
|
@@ -30,7 +30,7 @@ export default class SceneHierarchy extends Component<SceneHierarchyState> {
|
|
30
30
|
const hasScene = this.componentState.scene !== null;
|
31
31
|
const HierarchyName = 'Hierarchy - ' + (hasScene ? `${this.componentState.scene?.name}` : 'No Scene');
|
32
32
|
return (
|
33
|
-
<div id="
|
33
|
+
<div id="SidePanel" key="SidePanel">
|
34
34
|
{(
|
35
35
|
<>
|
36
36
|
<Accordion label={HierarchyName} open={true}>
|
@@ -41,9 +41,7 @@ export default class SceneHierarchy extends Component<SceneHierarchyState> {
|
|
41
41
|
</>
|
42
42
|
</Accordion>
|
43
43
|
|
44
|
-
<
|
45
|
-
<Inspector key="Inspector" three={this.three} />
|
46
|
-
</Accordion>
|
44
|
+
<Inspector three={this.three} />
|
47
45
|
</>
|
48
46
|
)}
|
49
47
|
</div>
|
@@ -60,7 +58,7 @@ export default class SceneHierarchy extends Component<SceneHierarchyState> {
|
|
60
58
|
|
61
59
|
// Getters / Setters
|
62
60
|
|
63
|
-
get componentState():
|
64
|
-
return this.state as
|
61
|
+
get componentState(): SidePanelState {
|
62
|
+
return this.state as SidePanelState;
|
65
63
|
}
|
66
64
|
}
|
@@ -0,0 +1,111 @@
|
|
1
|
+
import { useEffect, useState } from "react";
|
2
|
+
import { CoreComponentProps, RemoteObject } from "../types";
|
3
|
+
import { ToolEvents, debugDispatcher } from "../../global";
|
4
|
+
// Components
|
5
|
+
import './inspector.scss';
|
6
|
+
import Accordion from "../Accordion";
|
7
|
+
import InspectorField from './InspectorField';
|
8
|
+
// Utils
|
9
|
+
import { InspectCamera } from "./utils/InspectCamera";
|
10
|
+
import { InspectMaterial } from "./utils/InspectMaterial";
|
11
|
+
import { InspectTransform } from "./utils/InspectTransform";
|
12
|
+
import { InspectLight } from "./utils/InspectLight";
|
13
|
+
import { setItemProps } from "../utils";
|
14
|
+
import InspectAnimation from "./utils/InspectAnimation";
|
15
|
+
|
16
|
+
const defaultObject: RemoteObject = {
|
17
|
+
name: '',
|
18
|
+
uuid: '',
|
19
|
+
type: '',
|
20
|
+
visible: false,
|
21
|
+
matrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
|
22
|
+
animations: [],
|
23
|
+
material: undefined,
|
24
|
+
perspectiveCameraInfo: undefined,
|
25
|
+
orthographicCameraInfo: undefined,
|
26
|
+
lightInfo: undefined,
|
27
|
+
};
|
28
|
+
|
29
|
+
export default function Inspector(props: CoreComponentProps) {
|
30
|
+
const [currentObject, setCurrentObject] = useState<RemoteObject>(defaultObject);
|
31
|
+
|
32
|
+
useEffect(() => {
|
33
|
+
function onSelectItem(evt: any) {
|
34
|
+
const obj = evt.value as RemoteObject;
|
35
|
+
setCurrentObject(obj);
|
36
|
+
}
|
37
|
+
|
38
|
+
function setScene() {
|
39
|
+
setCurrentObject(defaultObject);
|
40
|
+
}
|
41
|
+
|
42
|
+
debugDispatcher.addEventListener(ToolEvents.SET_SCENE, setScene);
|
43
|
+
debugDispatcher.addEventListener(ToolEvents.SET_OBJECT, onSelectItem);
|
44
|
+
return () => {
|
45
|
+
debugDispatcher.removeEventListener(ToolEvents.SET_SCENE, setScene);
|
46
|
+
debugDispatcher.removeEventListener(ToolEvents.SET_OBJECT, onSelectItem);
|
47
|
+
};
|
48
|
+
}, []);
|
49
|
+
|
50
|
+
const objType = currentObject.type.toLowerCase();
|
51
|
+
|
52
|
+
return (
|
53
|
+
<Accordion label='Inspector' key='Inspector'>
|
54
|
+
<div id="Inspector" className={props.class}>
|
55
|
+
{currentObject.uuid.length > 0 && (
|
56
|
+
<>
|
57
|
+
{/* Core */}
|
58
|
+
<>
|
59
|
+
<InspectorField
|
60
|
+
type="string"
|
61
|
+
title="Name"
|
62
|
+
prop="name"
|
63
|
+
value={currentObject.name}
|
64
|
+
disabled={true}
|
65
|
+
/>
|
66
|
+
<InspectorField
|
67
|
+
type="string"
|
68
|
+
title="Type"
|
69
|
+
prop="type"
|
70
|
+
value={currentObject.type}
|
71
|
+
disabled={true}
|
72
|
+
/>
|
73
|
+
<InspectorField
|
74
|
+
type="string"
|
75
|
+
title="UUID"
|
76
|
+
prop="uuid"
|
77
|
+
value={currentObject.uuid}
|
78
|
+
disabled={true}
|
79
|
+
/>
|
80
|
+
<InspectorField
|
81
|
+
type="boolean"
|
82
|
+
title="Visible"
|
83
|
+
prop="visible"
|
84
|
+
value={currentObject.visible}
|
85
|
+
onChange={(key: string, value: any) => {
|
86
|
+
props.three.updateObject(currentObject.uuid, key, value);
|
87
|
+
const child = props.three.scene?.getObjectByProperty('uuid', currentObject.uuid);
|
88
|
+
if (child !== undefined) setItemProps(child, key, value);
|
89
|
+
}}
|
90
|
+
/>
|
91
|
+
</>
|
92
|
+
|
93
|
+
{/* Data */}
|
94
|
+
<>
|
95
|
+
{/* Transform */}
|
96
|
+
{InspectTransform(currentObject, props.three)}
|
97
|
+
{/* Animations */}
|
98
|
+
{currentObject.animations.length > 0 ? InspectAnimation(currentObject, props.three) : null}
|
99
|
+
{/* Cameras */}
|
100
|
+
{objType.search('camera') > -1 ? InspectCamera(currentObject, props.three) : null}
|
101
|
+
{/* Lights */}
|
102
|
+
{objType.search('light') > -1 ? InspectLight(currentObject, props.three) : null}
|
103
|
+
{/* Material */}
|
104
|
+
{objType.search('mesh') > -1 ? InspectMaterial(currentObject, props.three) : null}
|
105
|
+
</>
|
106
|
+
</>
|
107
|
+
)}
|
108
|
+
</div>
|
109
|
+
</Accordion>
|
110
|
+
);
|
111
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
import RemoteThree from "@/core/remote/RemoteThree";
|
2
|
+
import InspectorGroup from "../InspectorGroup";
|
3
|
+
import { InspectorFieldProps } from '../InspectorField';
|
4
|
+
import { AnimationClipInfo, RemoteObject } from '../../types';
|
5
|
+
import { setItemProps } from "../../utils";
|
6
|
+
|
7
|
+
export default function InspectAnimation(obj: RemoteObject, three: RemoteThree) {
|
8
|
+
const items: InspectorFieldProps[] = [];
|
9
|
+
obj.animations.forEach((value: AnimationClipInfo) => {
|
10
|
+
// Add animation
|
11
|
+
items.push({
|
12
|
+
title: 'Name',
|
13
|
+
type: 'string',
|
14
|
+
prop: 'name',
|
15
|
+
value: value.name,
|
16
|
+
disabled: true,
|
17
|
+
onChange: (prop: string, value: any) => {
|
18
|
+
three.updateObject(obj.uuid, prop, value);
|
19
|
+
const child = three.scene?.getObjectByProperty('uuid', obj.uuid);
|
20
|
+
if (child !== undefined) setItemProps(child, prop, value);
|
21
|
+
},
|
22
|
+
});
|
23
|
+
items.push({
|
24
|
+
title: 'Duration',
|
25
|
+
type: 'number',
|
26
|
+
prop: 'duration',
|
27
|
+
value: value.duration,
|
28
|
+
disabled: true,
|
29
|
+
onChange: (prop: string, value: any) => {
|
30
|
+
three.updateObject(obj.uuid, prop, value);
|
31
|
+
const child = three.scene?.getObjectByProperty('uuid', obj.uuid);
|
32
|
+
if (child !== undefined) setItemProps(child, prop, value);
|
33
|
+
},
|
34
|
+
});
|
35
|
+
items.push({
|
36
|
+
title: 'Blend Mode',
|
37
|
+
type: 'number',
|
38
|
+
prop: 'blendMode',
|
39
|
+
value: value.blendMode,
|
40
|
+
disabled: true,
|
41
|
+
onChange: (prop: string, value: any) => {
|
42
|
+
three.updateObject(obj.uuid, prop, value);
|
43
|
+
const child = three.scene?.getObjectByProperty('uuid', obj.uuid);
|
44
|
+
if (child !== undefined) setItemProps(child, prop, value);
|
45
|
+
},
|
46
|
+
});
|
47
|
+
});
|
48
|
+
return (
|
49
|
+
<InspectorGroup title="Animations" items={items} />
|
50
|
+
);
|
51
|
+
}
|
@@ -11,7 +11,7 @@ export interface ChildObjectProps extends CoreComponentProps {
|
|
11
11
|
three: RemoteThree
|
12
12
|
}
|
13
13
|
|
14
|
-
export interface
|
14
|
+
export interface SidePanelState {
|
15
15
|
scene?: Object3D
|
16
16
|
three: RemoteThree
|
17
17
|
}
|
@@ -71,6 +71,14 @@ export interface RemoteMaterial {
|
|
71
71
|
specularColor?: Color
|
72
72
|
}
|
73
73
|
|
74
|
+
// Animation Info
|
75
|
+
|
76
|
+
export interface AnimationClipInfo {
|
77
|
+
name: string;
|
78
|
+
duration: number;
|
79
|
+
blendMode: number;
|
80
|
+
}
|
81
|
+
|
74
82
|
// Camera Info
|
75
83
|
|
76
84
|
export interface PerspectiveCameraInfo {
|
@@ -114,6 +122,7 @@ export interface RemoteObject {
|
|
114
122
|
type: string
|
115
123
|
visible: boolean
|
116
124
|
matrix: number[] // based on Matrix4.elements
|
125
|
+
animations: AnimationClipInfo[]
|
117
126
|
material?: RemoteMaterial | RemoteMaterial[]
|
118
127
|
perspectiveCameraInfo?: PerspectiveCameraInfo
|
119
128
|
orthographicCameraInfo?: OrthographicCameraInfo
|