@babylonjs/inspector 9.29.0 → 9.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/inspector-bridge.mjs +4730 -4446
- package/bin/inspector-cli.mjs +4765 -3866
- package/lib/components/curveEditor/animatableAnimations.d.ts +27 -0
- package/lib/components/properties/nodes/gaussianSplattingProperties.d.ts +13 -2
- package/lib/{extensionsListService-DfE1ZOnF.js → extensionsListService-O8zrOnmL.js} +5 -2
- package/lib/{extensionsListService-DfE1ZOnF.js.map → extensionsListService-O8zrOnmL.js.map} +1 -1
- package/lib/gif-ut7hgn9U.js +45 -0
- package/lib/gif-ut7hgn9U.js.map +1 -0
- package/lib/{index-CZ1-Y-Rv.js → index-DbbhJJ1G.js} +321 -85
- package/lib/index-DbbhJJ1G.js.map +1 -0
- package/lib/index.js +4 -1
- package/lib/index.js.map +1 -1
- package/lib/lite/animationProperties-BKVw6_ls.js +95 -0
- package/lib/lite/animationProperties-BKVw6_ls.js.map +1 -0
- package/lib/lite/animationUtils.d.ts +47 -0
- package/lib/lite/components/properties/animationProperties.d.ts +48 -0
- package/lib/lite/directTextureBinding-C5MB2OV2.js +99 -0
- package/lib/lite/directTextureBinding-C5MB2OV2.js.map +1 -0
- package/lib/lite/dynamicMaterialField-L_nQAxAA.js +107 -0
- package/lib/lite/dynamicMaterialField-L_nQAxAA.js.map +1 -0
- package/lib/lite/engineExplorerService.d.ts +3 -1
- package/lib/lite/{extensionsListService-D1JivcAu.js → extensionsListService-Bl1rTNl1.js} +2 -2
- package/lib/lite/{extensionsListService-D1JivcAu.js.map → extensionsListService-Bl1rTNl1.js.map} +1 -1
- package/lib/lite/{index-D8vFySa7.js → index-Cy8gzpYG.js} +1453 -394
- package/lib/lite/index-Cy8gzpYG.js.map +1 -0
- package/lib/lite/index.js +1 -1
- package/lib/lite/nodeMaterialProperties-ELFMlzS1.js +182 -0
- package/lib/lite/nodeMaterialProperties-ELFMlzS1.js.map +1 -0
- package/lib/lite/pbrMaterialProperties-jfJddBxY.js +614 -0
- package/lib/lite/pbrMaterialProperties-jfJddBxY.js.map +1 -0
- package/lib/lite/services/panes/properties/animationPropertiesService.d.ts +5 -0
- package/lib/lite/services/panes/properties/materialPropertiesService.d.ts +3 -1
- package/lib/lite/services/panes/properties/materials/directTextureBinding.d.ts +29 -0
- package/lib/lite/services/panes/properties/materials/dynamicMaterialField.d.ts +35 -0
- package/lib/lite/services/panes/properties/materials/materialAdapterTypes.d.ts +11 -0
- package/lib/lite/services/panes/properties/materials/materialReachability.d.ts +9 -0
- package/lib/lite/services/panes/properties/materials/nodeMaterialProperties.d.ts +8 -0
- package/lib/lite/services/panes/properties/materials/pbrMaterialProperties.d.ts +8 -0
- package/lib/lite/services/panes/properties/materials/shaderMaterialProperties.d.ts +8 -0
- package/lib/lite/services/panes/properties/materials/standardMaterialProperties.d.ts +8 -0
- package/lib/lite/services/panes/properties/materials/useDirectMaterialOperations.d.ts +31 -0
- package/lib/lite/services/panes/properties/textureMetadataProperties.d.ts +14 -0
- package/lib/lite/services/panes/properties/texturePropertiesService.d.ts +3 -1
- package/lib/lite/services/panes/properties/useLatestAsyncOperation.d.ts +24 -0
- package/lib/lite/services/panes/scene/animationGroupExplorerService.d.ts +7 -0
- package/lib/lite/services/panes/scene/materialExplorerService.d.ts +2 -1
- package/lib/lite/services/panes/scene/materialTopologyBindings.d.ts +13 -0
- package/lib/lite/services/panes/scene/sceneResourceIndexService.d.ts +36 -0
- package/lib/lite/services/panes/scene/sceneResources.d.ts +55 -11
- package/lib/lite/services/panes/scene/textureExplorerService.d.ts +2 -1
- package/lib/lite/services/pickingService.d.ts +10 -0
- package/lib/lite/shaderMaterialProperties-CTH_KfBK.js +229 -0
- package/lib/lite/shaderMaterialProperties-CTH_KfBK.js.map +1 -0
- package/lib/lite/standardMaterialProperties-BbYdFX86.js +287 -0
- package/lib/lite/standardMaterialProperties-BbYdFX86.js.map +1 -0
- package/lib/lite/textureMetadataProperties-BdNmp0Pk.js +221 -0
- package/lib/lite/textureMetadataProperties-BdNmp0Pk.js.map +1 -0
- package/lib/lite/useDirectMaterialOperations-D6V7OtC1.js +83 -0
- package/lib/lite/useDirectMaterialOperations-D6V7OtC1.js.map +1 -0
- package/lib/lite/useLatestAsyncOperation-k59AgA3B.js +78 -0
- package/lib/lite/useLatestAsyncOperation-k59AgA3B.js.map +1 -0
- package/lib/{quickCreateToolsService-owfaw163.js → quickCreateToolsService-Cs46Amv7.js} +5 -2
- package/lib/{quickCreateToolsService-owfaw163.js.map → quickCreateToolsService-Cs46Amv7.js.map} +1 -1
- package/lib/{reflectorService-oIAxxpQt.js → reflectorService-C43FgOiC.js} +5 -2
- package/lib/{reflectorService-oIAxxpQt.js.map → reflectorService-C43FgOiC.js.map} +1 -1
- package/lib/services/panes/properties/gaussianSplattingDebugController.d.ts +46 -0
- package/package.json +8 -8
- package/lib/gif-5DieAkSF.js +0 -38
- package/lib/gif-5DieAkSF.js.map +0 -1
- package/lib/index-CZ1-Y-Rv.js.map +0 -1
- package/lib/lite/index-D8vFySa7.js.map +0 -1
|
@@ -2,7 +2,7 @@ import { Observable } from '@babylonjs/core/Misc/observable.js';
|
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
3
|
import { createContext, forwardRef, useContext, useState, useCallback, Component, useEffect, useMemo, useReducer, useRef, Children, isValidElement, useLayoutEffect, useImperativeHandle, cloneElement, createElement, Suspense, lazy } from 'react';
|
|
4
4
|
import { tokens, makeStyles, Tooltip as Tooltip$1, Button as Button$1, Spinner, useFluent, Accordion as Accordion$1, AccordionHeader, Subtitle2Stronger, AccordionPanel, Divider, MessageBar as MessageBar$1, MessageBarBody, AccordionItem, SearchBox as SearchBox$1, Portal, mergeClasses, createLightTheme, createDarkTheme, createDOMRenderer, FluentProvider, RendererProvider, TeachingPopover, TeachingPopoverSurface, TeachingPopoverHeader, TeachingPopoverBody, useId, useToastController, Toast, ToastTitle, Toaster, Menu, MenuTrigger, SplitButton, MenuPopover, MenuList, MenuItem, Toolbar as Toolbar$1, ToolbarRadioButton, MenuGroup, MenuGroupHeader, Link as Link$1, Caption1, Body1, ToggleButton as ToggleButton$1, InfoLabel as InfoLabel$1, Body1Strong, Checkbox as Checkbox$1, Switch as Switch$1, Dropdown as Dropdown$1, Option, useMergedRefs, Input, Slider as Slider$1, MenuItemRadio, Dialog, DialogSurface, DialogBody, DialogTitle, DialogContent, DialogActions, List as List$1, ListItem, useComboboxFilter, Combobox, MessageBarTitle, Popover as Popover$1, PopoverTrigger, PopoverSurface, Field, Textarea as Textarea$1, PresenceBadge, treeItemLevelToken, typographyStyles, FlatTree, FlatTreeItem, MenuDivider, TreeItemLayout, MenuItemCheckbox, ColorPicker, ColorArea, ColorSlider, AlphaSlider, ColorSwatch } from '@fluentui/react-components';
|
|
5
|
-
import { ErrorCircleRegular, EyeFilled, EyeOffRegular, CheckmarkFilled, EditRegular, FilterRegular, PinFilled, PinRegular, ArrowCircleUpRegular, PanelLeftExpandRegular, PanelRightExpandRegular, PanelLeftContractRegular, PanelRightContractRegular, PictureInPictureEnterRegular, MoreHorizontalRegular, LayoutColumnTwoFocusLeftFilled, LayoutColumnTwoSplitLeftFocusTopLeftFilled, LayoutColumnTwoSplitLeftFocusBottomLeftFilled, LayoutColumnTwoFocusRightFilled, LayoutColumnTwoSplitRightFocusTopRightFilled, LayoutColumnTwoSplitRightFocusBottomRightFilled, SettingsRegular, ChevronCircleRight16Regular, ChevronCircleRight20Regular, ChevronCircleDown16Regular, ChevronCircleDown20Regular, Copy16Regular, CopyRegular, DocumentTextRegular, ArrowBidirectionalUpDownFilled, ArrowClockwiseRegular, WeatherSunnyRegular, WeatherMoonRegular, InfoRegular, WarningRegular, CheckmarkCircleRegular, DeleteFilled, LinkDismissRegular, LinkEditRegular, AddRegular, DeleteRegular, ArrowUploadRegular, createFluentIcon, TextSortAscendingRegular, GlobeRegular, ArrowExpandAllRegular, ArrowCollapseAllRegular, ChevronRightRegular, CubeTreeRegular, EngineRegular, WindowRegular, TextFieldRegular, PersonSquareRegular, SaveRegular, ArrowUndoRegular, BracesRegular, BracesDismiss16Regular, CameraRegular, LightbulbRegular, EyeRegular, MyLocationRegular, LayerDiagonalPersonRegular, TextTRegular, ImageRegular } from '@fluentui/react-icons';
|
|
5
|
+
import { ErrorCircleRegular, EyeFilled, EyeOffRegular, CheckmarkFilled, EditRegular, FilterRegular, PinFilled, PinRegular, ArrowCircleUpRegular, PanelLeftExpandRegular, PanelRightExpandRegular, PanelLeftContractRegular, PanelRightContractRegular, PictureInPictureEnterRegular, MoreHorizontalRegular, LayoutColumnTwoFocusLeftFilled, LayoutColumnTwoSplitLeftFocusTopLeftFilled, LayoutColumnTwoSplitLeftFocusBottomLeftFilled, LayoutColumnTwoFocusRightFilled, LayoutColumnTwoSplitRightFocusTopRightFilled, LayoutColumnTwoSplitRightFocusBottomRightFilled, SettingsRegular, ChevronCircleRight16Regular, ChevronCircleRight20Regular, ChevronCircleDown16Regular, ChevronCircleDown20Regular, Copy16Regular, CopyRegular, DocumentTextRegular, ArrowBidirectionalUpDownFilled, ArrowClockwiseRegular, WeatherSunnyRegular, WeatherMoonRegular, InfoRegular, WarningRegular, CheckmarkCircleRegular, DeleteFilled, LinkDismissRegular, LinkEditRegular, AddRegular, DeleteRegular, ArrowUploadRegular, createFluentIcon, TextSortAscendingRegular, GlobeRegular, ArrowExpandAllRegular, ArrowCollapseAllRegular, ChevronRightRegular, CubeTreeRegular, EngineRegular, WindowRegular, TextFieldRegular, PersonSquareRegular, TargetRegular, SaveRegular, ArrowUndoRegular, BracesRegular, BracesDismiss16Regular, CameraRegular, PauseFilled, PlayFilled, StackRegular, FilmstripRegular, LightbulbRegular, EyeRegular, MyLocationRegular, LayerDiagonalPersonRegular, TextTRegular, ImageRegular } from '@fluentui/react-icons';
|
|
6
6
|
import { DataStorage } from '@babylonjs/core/Misc/dataStorage.js';
|
|
7
7
|
import { AsyncLock } from '@babylonjs/core/Misc/asyncLock.js';
|
|
8
8
|
import { Deferred } from '@babylonjs/core/Misc/deferred.js';
|
|
@@ -10,7 +10,7 @@ import { useResizeHandle } from '@fluentui-contrib/react-resize-handle';
|
|
|
10
10
|
import { Collapse as Collapse$1, Fade } from '@fluentui/react-motion-components-preview';
|
|
11
11
|
import { Logger } from '@babylonjs/core/Misc/logger.js';
|
|
12
12
|
import { createRoot } from 'react-dom/client';
|
|
13
|
-
import { getRenderingContexts, getRenderingContextKind,
|
|
13
|
+
import { getRenderingContexts, getRenderingContextKind, disposePicker, createGpuPicker, pickAsync, goToFrame, playAnimation, quatToEulerXYZTuple, eulerXYZToQuatTuple, getMaterialSource, getMaterialFamily, getShaderTexture, getPbrMetallicReflectance, getPbrClearCoat, getPbrSheen, getPbrIridescence, getPbrAnisotropy, getPbrSubsurface, getPbrTransmission, getStandardEmissiveTexture, getStandardBumpTexture, getStandardSpecularTexture, getStandardAmbientTexture, getStandardLightmapTexture, getStandardOpacityTexture, getStandardReflectionTexture, getStandardReflectionCubeTexture, getTextureMetadata, getTextureCoordinateIndex, hasTextureTransform, getTextureTransform, isMaterialView, setSubtreeVisible, spriteBlendOpaque, spriteBlendOneOne, spriteBlendMultiply, spriteBlendAdditive, spriteBlendPremultiplied, spriteBlendAlpha, removeFromScene, pauseAnimation, setParent, resizeEngine } from '@babylonjs/lite';
|
|
14
14
|
import { VirtualizerScrollView } from '@fluentui-contrib/react-virtualizer';
|
|
15
15
|
import { UniqueIdGenerator } from '@babylonjs/core/Misc/uniqueIdGenerator.js';
|
|
16
16
|
import { Color3, Color4 } from '@babylonjs/core/Maths/math.color.js';
|
|
@@ -3254,29 +3254,22 @@ const useStyles$g = makeStyles({
|
|
|
3254
3254
|
},
|
|
3255
3255
|
});
|
|
3256
3256
|
/**
|
|
3257
|
-
*
|
|
3258
|
-
*
|
|
3257
|
+
* Displays a controlled toggle button with icons.
|
|
3258
|
+
* The parent supplies the checked state through value; clicks request the opposite value through onChange.
|
|
3259
|
+
* If no uncheckedIcon is provided, the same icon is used for both states.
|
|
3259
3260
|
*
|
|
3260
|
-
* @param props
|
|
3261
|
-
* @returns
|
|
3261
|
+
* @param props The controlled state, change callback, icons, and button presentation.
|
|
3262
|
+
* @returns The toggle button.
|
|
3262
3263
|
*/
|
|
3263
3264
|
const ToggleButton = (props) => {
|
|
3264
3265
|
ToggleButton.displayName = "ToggleButton";
|
|
3265
3266
|
const { value, onChange, title, appearance = "subtle", ariaLabel } = props;
|
|
3266
3267
|
const { size } = useContext(ToolContext);
|
|
3267
3268
|
const classes = useStyles$g();
|
|
3268
|
-
const [checked, setChecked] = useState(value);
|
|
3269
3269
|
const toggle = useCallback(() => {
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
return enabled;
|
|
3274
|
-
});
|
|
3275
|
-
}, [onChange]);
|
|
3276
|
-
useEffect(() => {
|
|
3277
|
-
setChecked(props.value);
|
|
3278
|
-
}, [props.value]);
|
|
3279
|
-
return (jsx(Tooltip, { content: title ?? "", positioning: props.titlePositioning, children: jsx(ToggleButton$1, { className: classes.button, size: size, "aria-label": ariaLabel ?? title, icon: checked ? jsx(props.checkedIcon, {}) : props.uncheckedIcon ? jsx(props.uncheckedIcon, {}) : jsx(props.checkedIcon, {}), appearance: appearance, checked: checked, onClick: toggle }) }));
|
|
3270
|
+
onChange(!value);
|
|
3271
|
+
}, [value, onChange]);
|
|
3272
|
+
return (jsx(Tooltip, { content: title ?? "", positioning: props.titlePositioning, children: jsx(ToggleButton$1, { className: classes.button, size: size, "aria-label": ariaLabel ?? title, icon: value ? jsx(props.checkedIcon, {}) : props.uncheckedIcon ? jsx(props.uncheckedIcon, {}) : jsx(props.checkedIcon, {}), appearance: appearance, checked: value, onClick: toggle }) }));
|
|
3280
3273
|
};
|
|
3281
3274
|
|
|
3282
3275
|
const useInfoLabelStyles = makeStyles({
|
|
@@ -5137,7 +5130,7 @@ function MakeModularTool(options) {
|
|
|
5137
5130
|
}
|
|
5138
5131
|
// Register the extension list service (for browsing/installing extensions) if extension feeds are provided.
|
|
5139
5132
|
if (extensionFeeds.length > 0) {
|
|
5140
|
-
const { ExtensionListServiceDefinition } = await import('./extensionsListService-
|
|
5133
|
+
const { ExtensionListServiceDefinition } = await import('./extensionsListService-Bl1rTNl1.js');
|
|
5141
5134
|
serviceContainer.addService(ExtensionListServiceDefinition);
|
|
5142
5135
|
}
|
|
5143
5136
|
// Register all external services (that make up a unique tool).
|
|
@@ -5558,6 +5551,11 @@ const useStyles$9 = makeStyles({
|
|
|
5558
5551
|
minWidth: "fit-content",
|
|
5559
5552
|
maxWidth: "350px",
|
|
5560
5553
|
},
|
|
5554
|
+
compactOption: {
|
|
5555
|
+
fontSize: tokens.fontSizeBase200,
|
|
5556
|
+
lineHeight: tokens.lineHeightBase200,
|
|
5557
|
+
padding: `${tokens.spacingVerticalXXS} ${tokens.spacingHorizontalS}`,
|
|
5558
|
+
},
|
|
5561
5559
|
});
|
|
5562
5560
|
/**
|
|
5563
5561
|
* Wrapper around a Fluent ComboBox that allows for filtering options.
|
|
@@ -5581,13 +5579,13 @@ const ComboBox = forwardRef((props, ref) => {
|
|
|
5581
5579
|
noOptionsMessage: "No items match your search.",
|
|
5582
5580
|
optionToReactKey: (option) => option.value,
|
|
5583
5581
|
optionToText: (option) => option.children,
|
|
5584
|
-
renderOption: (option) => (jsx(Option, { value: option.value, text: option.children, children: option.children }, option.value)),
|
|
5582
|
+
renderOption: (option) => (jsx(Option, { value: option.value, text: option.children, className: size === "small" ? styles.compactOption : undefined, children: option.children }, option.value)),
|
|
5585
5583
|
});
|
|
5586
5584
|
const onOptionSelect = (_e, data) => {
|
|
5587
5585
|
setQuery(data.optionText ?? "");
|
|
5588
5586
|
data.optionValue && props.onChange(data.optionValue);
|
|
5589
5587
|
};
|
|
5590
|
-
return (jsxs("div", { className: styles.root, children: [jsx("label", { id: comboId, children: props.label }), jsx(Combobox, { ref: ref, defaultOpen: props.defaultOpen, size: size, root: { className: styles.comboBox }, input: { className: styles.input }, listbox: { className: styles.listbox }, onOptionSelect: onOptionSelect, "aria-labelledby": comboId, placeholder: "Search..", onChange: (ev) => setQuery(ev.target.value), value: query, children: children })] }));
|
|
5588
|
+
return (jsxs("div", { className: styles.root, children: [jsx("label", { id: comboId, children: props.label }), jsx(Combobox, { ref: ref, defaultOpen: props.defaultOpen, disabled: props.disabled, size: size, root: { className: styles.comboBox }, input: { className: styles.input }, listbox: { className: styles.listbox }, onOptionSelect: onOptionSelect, "aria-label": props.ariaLabel, "aria-labelledby": props.ariaLabel ? undefined : comboId, placeholder: "Search..", onChange: (ev) => setQuery(ev.target.value), value: query, children: children })] }));
|
|
5591
5589
|
});
|
|
5592
5590
|
|
|
5593
5591
|
const useDraggableStyles = makeStyles({
|
|
@@ -5661,26 +5659,18 @@ const useStyles$8 = makeStyles({
|
|
|
5661
5659
|
},
|
|
5662
5660
|
});
|
|
5663
5661
|
/**
|
|
5664
|
-
*
|
|
5665
|
-
*
|
|
5666
|
-
* @
|
|
5667
|
-
* @returns EntitySelector component
|
|
5662
|
+
* Displays a linked resource with one unlink-or-edit action, or a selector when unlinked.
|
|
5663
|
+
* @param props Resource identity, selection, navigation, and supported actions.
|
|
5664
|
+
* @returns The linked value or its replacement selector.
|
|
5668
5665
|
*/
|
|
5669
|
-
function
|
|
5670
|
-
const { value,
|
|
5671
|
-
const onChange = props.onChange;
|
|
5666
|
+
function ResourceSelector(props) {
|
|
5667
|
+
const { value, getEntities, getName, getId, filter, onSelect, onClear, onLink, disabled, ariaLabel, showEmptySelector } = props;
|
|
5672
5668
|
const classes = useStyles$8();
|
|
5673
5669
|
const comboBoxRef = useRef(null);
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
.map((entity) => ({
|
|
5679
|
-
label: getName(entity)?.toString() || "",
|
|
5680
|
-
value: entity.uniqueId.toString(),
|
|
5681
|
-
}))
|
|
5682
|
-
.sort((a, b) => a.label.localeCompare(b.label));
|
|
5683
|
-
}, [getEntities, getName, filter]);
|
|
5670
|
+
const options = useMemo(() => getEntities()
|
|
5671
|
+
.filter((entity) => !filter || filter(entity))
|
|
5672
|
+
.map((entity) => ({ label: getName(entity)?.toString() || "", value: getId(entity) }))
|
|
5673
|
+
.sort((a, b) => a.label.localeCompare(b.label)), [getEntities, getName, getId, filter]);
|
|
5684
5674
|
const [isEditing, setIsEditing] = useState(false);
|
|
5685
5675
|
const [enteringEditMode, pulseEnteringEditMode] = useImpulse();
|
|
5686
5676
|
useEffect(() => {
|
|
@@ -5688,28 +5678,37 @@ function EntitySelector(props) {
|
|
|
5688
5678
|
comboBoxRef.current?.focus();
|
|
5689
5679
|
}
|
|
5690
5680
|
}, [enteringEditMode]);
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5681
|
+
if (value !== null && !isEditing) {
|
|
5682
|
+
return (jsxs("div", { className: classes.linkDiv, children: [jsx(Tooltip$1, { content: getName(value), relationship: "label", children: jsx(Link, { className: classes.link, value: getName(value), onLink: onLink ? () => onLink(value) : undefined, "aria-label": onLink && ariaLabel ? `${ariaLabel}: open ${getName(value)}` : undefined }) }), onClear ? (jsx(Tooltip$1, { content: "Unlink", relationship: "label", children: jsx(Button, { icon: LinkDismissRegular, ariaLabel: ariaLabel ? `Clear ${ariaLabel}` : "Unlink", disabled: disabled, onClick: () => {
|
|
5683
|
+
pulseEnteringEditMode(true);
|
|
5684
|
+
onClear();
|
|
5685
|
+
} }) })) : onSelect ? (jsx(Tooltip$1, { content: "Edit Link", relationship: "label", children: jsx(Button, { icon: LinkEditRegular, ariaLabel: ariaLabel ? `Change ${ariaLabel}` : "Edit Link", disabled: disabled, onClick: () => {
|
|
5686
|
+
pulseEnteringEditMode(true);
|
|
5687
|
+
setIsEditing(true);
|
|
5688
|
+
} }) })) : undefined] }));
|
|
5689
|
+
}
|
|
5690
|
+
if (!onSelect && !showEmptySelector) {
|
|
5691
|
+
return jsx(Link, { value: "None" });
|
|
5692
|
+
}
|
|
5693
|
+
return (jsx(ComboBox, { ref: comboBoxRef, defaultOpen: enteringEditMode, label: "", ariaLabel: ariaLabel, disabled: disabled, options: options, value: value !== null ? getId(value) : "", onChange: (id) => {
|
|
5694
|
+
onSelect?.(getEntities().find((entity) => getId(entity) === id) ?? null);
|
|
5695
|
+
setIsEditing(false);
|
|
5696
|
+
} }));
|
|
5697
|
+
}
|
|
5698
|
+
ResourceSelector.displayName = "ResourceSelector";
|
|
5699
|
+
|
|
5700
|
+
const GetEntityId$1 = (entity) => entity.uniqueId.toString();
|
|
5701
|
+
/**
|
|
5702
|
+
* A generic primitive component with a ComboBox for selecting from a list of entities.
|
|
5703
|
+
* Supports entities with duplicate names by using uniqueId for identity.
|
|
5704
|
+
* @param props ChooseEntityProps
|
|
5705
|
+
* @returns EntitySelector component
|
|
5706
|
+
*/
|
|
5707
|
+
function EntitySelector(props) {
|
|
5708
|
+
const { value, onLink, getEntities, getName, filter, defaultValue, disabled } = props;
|
|
5709
|
+
const onChange = props.onChange;
|
|
5710
|
+
const filterEntity = useCallback((entity) => entity.uniqueId !== undefined && (!filter || filter(entity)), [filter]);
|
|
5711
|
+
return (jsx(ResourceSelector, { value: value, getEntities: getEntities, getName: getName, getId: GetEntityId$1, filter: filterEntity, onSelect: onChange, onClear: onChange && defaultValue !== undefined ? () => onChange(defaultValue) : undefined, onLink: onLink, disabled: disabled, showEmptySelector: true }));
|
|
5713
5712
|
}
|
|
5714
5713
|
EntitySelector.displayName = "EntitySelector";
|
|
5715
5714
|
|
|
@@ -7101,10 +7100,19 @@ const ActionCommand = (props) => {
|
|
|
7101
7100
|
};
|
|
7102
7101
|
const ToggleCommand = (props) => {
|
|
7103
7102
|
const { command } = props;
|
|
7103
|
+
const readCommandState = useCallback(() => [command.icon, command.isEnabled], [command]);
|
|
7104
7104
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
7105
|
-
const [Icon, isEnabled]
|
|
7105
|
+
const [[Icon, isEnabled], setCommandState] = useState(readCommandState);
|
|
7106
|
+
useEffect(() => {
|
|
7107
|
+
const observer = command.onChange?.add(() => setCommandState(readCommandState()));
|
|
7108
|
+
setCommandState(readCommandState());
|
|
7109
|
+
return () => observer?.remove();
|
|
7110
|
+
}, [command, readCommandState]);
|
|
7106
7111
|
// TODO-iv2: Consolidate icon prop passing approach for inspector and shared components
|
|
7107
|
-
return (jsx(ToggleButton, { appearance: "transparent", title: GetCommandDescription(command), titlePositioning: "after", checkedIcon: Icon, value: isEnabled, onChange: (
|
|
7112
|
+
return (jsx(ToggleButton, { appearance: "transparent", title: GetCommandDescription(command), titlePositioning: "after", checkedIcon: Icon, value: isEnabled, onChange: (value) => {
|
|
7113
|
+
command.isEnabled = value;
|
|
7114
|
+
setCommandState(readCommandState());
|
|
7115
|
+
} }));
|
|
7108
7116
|
};
|
|
7109
7117
|
// This "placeholder" command has a blank icon and is a no-op. It is used for aside
|
|
7110
7118
|
// alignment when some toggle commands are enabled. See more details on the commands
|
|
@@ -7587,6 +7595,7 @@ function UntypeRenderingContextNodeProvider(provider) {
|
|
|
7587
7595
|
predicate: (context) => provider.predicate(context),
|
|
7588
7596
|
getNodes: (context) => (provider.predicate(context) ? provider.getNodes(context) : []),
|
|
7589
7597
|
getSnapshot: (context) => (provider.predicate(context) ? provider.getSnapshot(context) : []),
|
|
7598
|
+
onChanged: provider.onChanged,
|
|
7590
7599
|
};
|
|
7591
7600
|
}
|
|
7592
7601
|
// The predicate validates the subtype before the presentation is requested. Wrapping the icon then
|
|
@@ -7793,6 +7802,7 @@ const EngineExplorerServiceDefinition = {
|
|
|
7793
7802
|
order: provider.order,
|
|
7794
7803
|
predicate: (parent) => typeof parent === "object" && parent !== null && isRenderingContext(parent) && untypedProvider.predicate(parent),
|
|
7795
7804
|
getNodes: untypedProvider.getNodes,
|
|
7805
|
+
onChanged: untypedProvider.onChanged,
|
|
7796
7806
|
});
|
|
7797
7807
|
let isRegistered = true;
|
|
7798
7808
|
return {
|
|
@@ -7842,6 +7852,337 @@ const EngineSelectionServiceDefinition = {
|
|
|
7842
7852
|
},
|
|
7843
7853
|
};
|
|
7844
7854
|
|
|
7855
|
+
function GetSceneContexts(engine) {
|
|
7856
|
+
return engine.surfaces.flatMap((surface) => getRenderingContexts(surface).filter((context) => getRenderingContextKind(context) === "scene"));
|
|
7857
|
+
}
|
|
7858
|
+
function IsSceneNode(entity) {
|
|
7859
|
+
return (typeof entity === "object" &&
|
|
7860
|
+
entity !== null &&
|
|
7861
|
+
"name" in entity &&
|
|
7862
|
+
"children" in entity &&
|
|
7863
|
+
"position" in entity &&
|
|
7864
|
+
"rotationQuaternion" in entity &&
|
|
7865
|
+
"scaling" in entity &&
|
|
7866
|
+
"parent" in entity);
|
|
7867
|
+
}
|
|
7868
|
+
function IsMesh(entity) {
|
|
7869
|
+
return IsSceneNode(entity) && "material" in entity && "receiveShadows" in entity;
|
|
7870
|
+
}
|
|
7871
|
+
function IsCamera(entity) {
|
|
7872
|
+
return typeof entity === "object" && entity !== null && "fov" in entity && "nearPlane" in entity && "farPlane" in entity && "children" in entity && "worldMatrix" in entity;
|
|
7873
|
+
}
|
|
7874
|
+
function IsArcRotateCamera(entity) {
|
|
7875
|
+
return IsCamera(entity) && "alpha" in entity && "beta" in entity && "radius" in entity && "target" in entity;
|
|
7876
|
+
}
|
|
7877
|
+
function IsFreeCamera(entity) {
|
|
7878
|
+
return IsCamera(entity) && "position" in entity && "target" in entity && "speed" in entity;
|
|
7879
|
+
}
|
|
7880
|
+
function IsLight(entity) {
|
|
7881
|
+
return typeof entity === "object" && entity !== null && "lightType" in entity && "children" in entity && "parent" in entity && "worldMatrix" in entity;
|
|
7882
|
+
}
|
|
7883
|
+
function IsDirectionalLight(entity) {
|
|
7884
|
+
return IsLight(entity) && entity.lightType === "directional";
|
|
7885
|
+
}
|
|
7886
|
+
function IsPointLight(entity) {
|
|
7887
|
+
return IsLight(entity) && entity.lightType === "point";
|
|
7888
|
+
}
|
|
7889
|
+
function IsSpotLight(entity) {
|
|
7890
|
+
return IsLight(entity) && entity.lightType === "spot";
|
|
7891
|
+
}
|
|
7892
|
+
function IsHemisphericLight(entity) {
|
|
7893
|
+
return IsLight(entity) && entity.lightType === "hemispheric";
|
|
7894
|
+
}
|
|
7895
|
+
function GetSceneNodes(scene) {
|
|
7896
|
+
const nodes = new Set();
|
|
7897
|
+
const addNode = (node) => {
|
|
7898
|
+
if (nodes.has(node)) {
|
|
7899
|
+
return;
|
|
7900
|
+
}
|
|
7901
|
+
nodes.add(node);
|
|
7902
|
+
for (const child of node.children) {
|
|
7903
|
+
addNode(child);
|
|
7904
|
+
}
|
|
7905
|
+
};
|
|
7906
|
+
for (const mesh of scene.meshes) {
|
|
7907
|
+
let root = mesh;
|
|
7908
|
+
while (IsSceneNode(root.parent)) {
|
|
7909
|
+
root = root.parent;
|
|
7910
|
+
}
|
|
7911
|
+
addNode(root);
|
|
7912
|
+
}
|
|
7913
|
+
return [...nodes];
|
|
7914
|
+
}
|
|
7915
|
+
function GetSceneNodeRoots(scene) {
|
|
7916
|
+
const nodes = GetSceneNodes(scene);
|
|
7917
|
+
const nodeSet = new Set(nodes);
|
|
7918
|
+
return nodes.filter((node) => !IsSceneNode(node.parent) || !nodeSet.has(node.parent));
|
|
7919
|
+
}
|
|
7920
|
+
function IsSceneNodeDescendantOf(node, ancestor) {
|
|
7921
|
+
let parent = node.parent;
|
|
7922
|
+
while (typeof parent === "object" && parent !== null) {
|
|
7923
|
+
if (parent === ancestor) {
|
|
7924
|
+
return true;
|
|
7925
|
+
}
|
|
7926
|
+
if (!IsSceneNode(parent)) {
|
|
7927
|
+
return false;
|
|
7928
|
+
}
|
|
7929
|
+
parent = parent.parent;
|
|
7930
|
+
}
|
|
7931
|
+
return false;
|
|
7932
|
+
}
|
|
7933
|
+
function SetVector3Value(target, value) {
|
|
7934
|
+
const x = "x" in value ? value.x : value[0];
|
|
7935
|
+
const y = "x" in value ? value.y : value[1];
|
|
7936
|
+
const z = "x" in value ? value.z : value[2];
|
|
7937
|
+
const observableTarget = target;
|
|
7938
|
+
if (typeof observableTarget.set === "function") {
|
|
7939
|
+
observableTarget.set(x, y, z);
|
|
7940
|
+
}
|
|
7941
|
+
else {
|
|
7942
|
+
target.x = x;
|
|
7943
|
+
target.y = y;
|
|
7944
|
+
target.z = z;
|
|
7945
|
+
}
|
|
7946
|
+
}
|
|
7947
|
+
function SetQuaternionValue(target, value) {
|
|
7948
|
+
const x = "x" in value ? value.x : value[0];
|
|
7949
|
+
const y = "x" in value ? value.y : value[1];
|
|
7950
|
+
const z = "x" in value ? value.z : value[2];
|
|
7951
|
+
const w = "x" in value ? value.w : value[3];
|
|
7952
|
+
const observableTarget = target;
|
|
7953
|
+
if (typeof observableTarget.set === "function") {
|
|
7954
|
+
observableTarget.set(x, y, z, w);
|
|
7955
|
+
}
|
|
7956
|
+
else {
|
|
7957
|
+
target.x = x;
|
|
7958
|
+
target.y = y;
|
|
7959
|
+
target.z = z;
|
|
7960
|
+
target.w = w;
|
|
7961
|
+
}
|
|
7962
|
+
}
|
|
7963
|
+
function GetLightDisplayName(light, index) {
|
|
7964
|
+
const typeName = `${light.lightType.charAt(0).toUpperCase()}${light.lightType.slice(1)}`;
|
|
7965
|
+
return `${typeName} Light ${index + 1}`;
|
|
7966
|
+
}
|
|
7967
|
+
function GetShadowGeneratorDisplayName(scene, shadowGenerator) {
|
|
7968
|
+
const lightIndex = scene.lights.findIndex((light) => light.shadowGenerator === shadowGenerator);
|
|
7969
|
+
return lightIndex === -1 ? `Shadow Generator ${scene.shadowGenerators.indexOf(shadowGenerator) + 1}` : `${GetLightDisplayName(scene.lights[lightIndex], lightIndex)} Shadows`;
|
|
7970
|
+
}
|
|
7971
|
+
|
|
7972
|
+
/**
|
|
7973
|
+
* Adds opt-in mesh picking to the canvases hosting Babylon Lite scenes.
|
|
7974
|
+
* Picking uses CSS canvas coordinates and updates the shared Inspector selection.
|
|
7975
|
+
*/
|
|
7976
|
+
const PickingServiceDefinition = {
|
|
7977
|
+
friendlyName: "Babylon Lite Picking",
|
|
7978
|
+
consumes: [EngineContextIdentity, ShellServiceIdentity, SelectionServiceIdentity, WatcherServiceIdentity],
|
|
7979
|
+
factory: (engineContext, shellService, selectionService, watcherService) => {
|
|
7980
|
+
const onChanged = new Observable();
|
|
7981
|
+
const pickers = new Map();
|
|
7982
|
+
const canvasBindings = new Map();
|
|
7983
|
+
const documentBindings = new Map();
|
|
7984
|
+
let toolbarRegistration;
|
|
7985
|
+
let enabled = false;
|
|
7986
|
+
let disposed = false;
|
|
7987
|
+
let generation = 0;
|
|
7988
|
+
const retirePicker = (scene, state) => {
|
|
7989
|
+
pickers.delete(scene);
|
|
7990
|
+
state.retired = true;
|
|
7991
|
+
// GPU readback cannot be cancelled. Keep its buffers alive until all outstanding picks finish.
|
|
7992
|
+
if (state.pending === 0) {
|
|
7993
|
+
disposePicker(state.picker);
|
|
7994
|
+
}
|
|
7995
|
+
};
|
|
7996
|
+
const pickCanvasAsync = async (canvas, x, y) => {
|
|
7997
|
+
const requestGeneration = ++generation;
|
|
7998
|
+
const scenes = GetSceneContexts(engineContext.engine).filter((scene) => scene.surface.canvas === canvas);
|
|
7999
|
+
const isCurrent = () => !disposed && enabled && generation === requestGeneration;
|
|
8000
|
+
try {
|
|
8001
|
+
// Later scenes render over earlier ones on the same surface.
|
|
8002
|
+
for (const scene of scenes.reverse()) {
|
|
8003
|
+
if (!isCurrent()) {
|
|
8004
|
+
return;
|
|
8005
|
+
}
|
|
8006
|
+
const camera = scene.camera;
|
|
8007
|
+
if (!camera || scene.meshes.length === 0) {
|
|
8008
|
+
continue;
|
|
8009
|
+
}
|
|
8010
|
+
let state = pickers.get(scene);
|
|
8011
|
+
if (!state) {
|
|
8012
|
+
state = { picker: createGpuPicker(scene), pending: 0, retired: false };
|
|
8013
|
+
pickers.set(scene, state);
|
|
8014
|
+
}
|
|
8015
|
+
state.pending++;
|
|
8016
|
+
let result;
|
|
8017
|
+
try {
|
|
8018
|
+
// Lite serializes overlapping requests on each picker. A mesh filter also excludes
|
|
8019
|
+
// contributors (such as billboards) that do not yet have Inspector selection support.
|
|
8020
|
+
// eslint-disable-next-line no-await-in-loop
|
|
8021
|
+
result = await pickAsync(state.picker, x, y, { filter: (mesh) => mesh.visible !== false });
|
|
8022
|
+
}
|
|
8023
|
+
finally {
|
|
8024
|
+
state.pending--;
|
|
8025
|
+
if (state.retired && state.pending === 0) {
|
|
8026
|
+
disposePicker(state.picker);
|
|
8027
|
+
}
|
|
8028
|
+
}
|
|
8029
|
+
if (!isCurrent() || state.retired || scene.camera !== camera || !GetSceneContexts(engineContext.engine).includes(scene)) {
|
|
8030
|
+
return;
|
|
8031
|
+
}
|
|
8032
|
+
if (result.hit && result.pickedMesh && scene.meshes.some((mesh) => mesh === result.pickedMesh && mesh.visible !== false && mesh.pickable !== false)) {
|
|
8033
|
+
selectionService.selectedEntity = result.pickedMesh;
|
|
8034
|
+
return;
|
|
8035
|
+
}
|
|
8036
|
+
}
|
|
8037
|
+
}
|
|
8038
|
+
catch (error) {
|
|
8039
|
+
Logger.Warn(`Babylon Lite GPU picking failed: ${error}`);
|
|
8040
|
+
}
|
|
8041
|
+
};
|
|
8042
|
+
const bindCanvas = (canvas) => {
|
|
8043
|
+
const originalCursor = canvas.style.cursor;
|
|
8044
|
+
canvas.style.cursor = "crosshair";
|
|
8045
|
+
let pointer;
|
|
8046
|
+
const isDragged = (event) => !!pointer && Math.hypot(event.clientX - pointer.x, event.clientY - pointer.y) > 5;
|
|
8047
|
+
const onPointerDown = (event) => {
|
|
8048
|
+
pointer = event.isPrimary && event.button === 0 ? { id: event.pointerId, x: event.clientX, y: event.clientY, dragged: false } : undefined;
|
|
8049
|
+
};
|
|
8050
|
+
const onPointerMove = (event) => {
|
|
8051
|
+
if (pointer?.id === event.pointerId && isDragged(event)) {
|
|
8052
|
+
pointer.dragged = true;
|
|
8053
|
+
}
|
|
8054
|
+
};
|
|
8055
|
+
const onPointerCancel = () => {
|
|
8056
|
+
pointer = undefined;
|
|
8057
|
+
};
|
|
8058
|
+
const onPointerUp = (event) => {
|
|
8059
|
+
const tap = pointer?.id === event.pointerId && event.button === 0 && !pointer.dragged && !isDragged(event);
|
|
8060
|
+
pointer = undefined;
|
|
8061
|
+
if (!tap) {
|
|
8062
|
+
return;
|
|
8063
|
+
}
|
|
8064
|
+
const rect = canvas.getBoundingClientRect();
|
|
8065
|
+
if (rect.width <= 0 || rect.height <= 0) {
|
|
8066
|
+
return;
|
|
8067
|
+
}
|
|
8068
|
+
// Account for CSS scaling without applying DPR; Lite's picker handles backing-store scaling.
|
|
8069
|
+
const x = ((event.clientX - rect.left) * (canvas.offsetWidth || canvas.clientWidth)) / rect.width - canvas.clientLeft;
|
|
8070
|
+
const y = ((event.clientY - rect.top) * (canvas.offsetHeight || canvas.clientHeight)) / rect.height - canvas.clientTop;
|
|
8071
|
+
if (x < 0 || y < 0 || x >= canvas.clientWidth || y >= canvas.clientHeight) {
|
|
8072
|
+
return;
|
|
8073
|
+
}
|
|
8074
|
+
void pickCanvasAsync(canvas, x, y);
|
|
8075
|
+
};
|
|
8076
|
+
canvas.addEventListener("pointerdown", onPointerDown);
|
|
8077
|
+
canvas.addEventListener("pointermove", onPointerMove);
|
|
8078
|
+
canvas.addEventListener("pointerup", onPointerUp);
|
|
8079
|
+
canvas.addEventListener("pointercancel", onPointerCancel);
|
|
8080
|
+
canvas.addEventListener("pointerleave", onPointerCancel);
|
|
8081
|
+
return () => {
|
|
8082
|
+
canvas.removeEventListener("pointerdown", onPointerDown);
|
|
8083
|
+
canvas.removeEventListener("pointermove", onPointerMove);
|
|
8084
|
+
canvas.removeEventListener("pointerup", onPointerUp);
|
|
8085
|
+
canvas.removeEventListener("pointercancel", onPointerCancel);
|
|
8086
|
+
canvas.removeEventListener("pointerleave", onPointerCancel);
|
|
8087
|
+
canvas.style.cursor = originalCursor;
|
|
8088
|
+
};
|
|
8089
|
+
};
|
|
8090
|
+
const refresh = () => {
|
|
8091
|
+
const scenes = disposed ? [] : GetSceneContexts(engineContext.engine);
|
|
8092
|
+
if (scenes.length === 0) {
|
|
8093
|
+
enabled = false;
|
|
8094
|
+
toolbarRegistration?.dispose();
|
|
8095
|
+
toolbarRegistration = undefined;
|
|
8096
|
+
}
|
|
8097
|
+
else if (!toolbarRegistration) {
|
|
8098
|
+
toolbarRegistration = shellService.addToolbarItem({
|
|
8099
|
+
key: "Picking Service",
|
|
8100
|
+
verticalLocation: "top",
|
|
8101
|
+
horizontalLocation: "left",
|
|
8102
|
+
teachingMoment: false,
|
|
8103
|
+
component: pickingToolbar,
|
|
8104
|
+
});
|
|
8105
|
+
}
|
|
8106
|
+
const activeScenes = enabled ? scenes : [];
|
|
8107
|
+
// DOM canvas constructors differ across windows; offscreen canvases have no ownerDocument.
|
|
8108
|
+
const canvases = new Set(activeScenes.map((scene) => scene.surface.canvas).filter((canvas) => "ownerDocument" in canvas));
|
|
8109
|
+
const documents = new Set([...canvases].map((canvas) => canvas.ownerDocument));
|
|
8110
|
+
for (const [canvas, unbind] of canvasBindings) {
|
|
8111
|
+
if (!canvases.has(canvas)) {
|
|
8112
|
+
unbind();
|
|
8113
|
+
canvasBindings.delete(canvas);
|
|
8114
|
+
}
|
|
8115
|
+
}
|
|
8116
|
+
for (const canvas of canvases) {
|
|
8117
|
+
if (!canvasBindings.has(canvas)) {
|
|
8118
|
+
canvasBindings.set(canvas, bindCanvas(canvas));
|
|
8119
|
+
}
|
|
8120
|
+
}
|
|
8121
|
+
for (const [document, unbind] of documentBindings) {
|
|
8122
|
+
if (!documents.has(document)) {
|
|
8123
|
+
unbind();
|
|
8124
|
+
documentBindings.delete(document);
|
|
8125
|
+
}
|
|
8126
|
+
}
|
|
8127
|
+
for (const document of documents) {
|
|
8128
|
+
if (!documentBindings.has(document)) {
|
|
8129
|
+
const onKeyDown = (event) => {
|
|
8130
|
+
if (event.key === "Escape") {
|
|
8131
|
+
setEnabled(false);
|
|
8132
|
+
}
|
|
8133
|
+
};
|
|
8134
|
+
document.addEventListener("keydown", onKeyDown);
|
|
8135
|
+
documentBindings.set(document, () => document.removeEventListener("keydown", onKeyDown));
|
|
8136
|
+
}
|
|
8137
|
+
}
|
|
8138
|
+
for (const [scene, state] of pickers) {
|
|
8139
|
+
if (!activeScenes.includes(scene)) {
|
|
8140
|
+
retirePicker(scene, state);
|
|
8141
|
+
}
|
|
8142
|
+
}
|
|
8143
|
+
};
|
|
8144
|
+
const setEnabled = (value) => {
|
|
8145
|
+
if (disposed || enabled === value) {
|
|
8146
|
+
return;
|
|
8147
|
+
}
|
|
8148
|
+
enabled = value;
|
|
8149
|
+
generation++;
|
|
8150
|
+
refresh();
|
|
8151
|
+
onChanged.notifyObservers();
|
|
8152
|
+
};
|
|
8153
|
+
const pickingToolbar = () => {
|
|
8154
|
+
const pickingEnabled = useObservableState(() => enabled, onChanged);
|
|
8155
|
+
useKeyListener({
|
|
8156
|
+
onKeyDown: (event) => {
|
|
8157
|
+
if (event.key === "Escape") {
|
|
8158
|
+
setEnabled(false);
|
|
8159
|
+
}
|
|
8160
|
+
},
|
|
8161
|
+
});
|
|
8162
|
+
return (jsx(ToggleButton, { title: `${pickingEnabled ? "Disable" : "Enable"} Picking`, appearance: "transparent", checkedIcon: TargetRegular, value: pickingEnabled, onChange: setEnabled }));
|
|
8163
|
+
};
|
|
8164
|
+
const selectionObserver = selectionService.onSelectedEntityChanged.add(() => generation++);
|
|
8165
|
+
const topologyWatcher = watcherService.watchValue(() => GetSceneContexts(engineContext.engine), () => {
|
|
8166
|
+
generation++;
|
|
8167
|
+
refresh();
|
|
8168
|
+
}, (left, right) => left.length === right.length && left.every((scene, index) => scene === right[index]));
|
|
8169
|
+
refresh();
|
|
8170
|
+
return {
|
|
8171
|
+
dispose: () => {
|
|
8172
|
+
if (disposed) {
|
|
8173
|
+
return;
|
|
8174
|
+
}
|
|
8175
|
+
disposed = true;
|
|
8176
|
+
generation++;
|
|
8177
|
+
refresh();
|
|
8178
|
+
topologyWatcher.dispose();
|
|
8179
|
+
selectionObserver.remove();
|
|
8180
|
+
onChanged.clear();
|
|
8181
|
+
},
|
|
8182
|
+
};
|
|
8183
|
+
},
|
|
8184
|
+
};
|
|
8185
|
+
|
|
7845
8186
|
/**
|
|
7846
8187
|
* Translates a property value to react state, updating the state whenever the property changes.
|
|
7847
8188
|
* @param target The object containing the property to observe.
|
|
@@ -8226,123 +8567,291 @@ const EnginePropertiesServiceDefinition = {
|
|
|
8226
8567
|
},
|
|
8227
8568
|
};
|
|
8228
8569
|
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
-
|
|
8238
|
-
"rotationQuaternion" in entity &&
|
|
8239
|
-
"scaling" in entity &&
|
|
8240
|
-
"parent" in entity);
|
|
8241
|
-
}
|
|
8242
|
-
function IsMesh(entity) {
|
|
8243
|
-
return IsSceneNode(entity) && "material" in entity && "receiveShadows" in entity;
|
|
8244
|
-
}
|
|
8245
|
-
function IsCamera(entity) {
|
|
8246
|
-
return typeof entity === "object" && entity !== null && "fov" in entity && "nearPlane" in entity && "farPlane" in entity && "children" in entity && "worldMatrix" in entity;
|
|
8570
|
+
const PrettyJSONIndent = 2;
|
|
8571
|
+
function IsParsable(metadata) {
|
|
8572
|
+
try {
|
|
8573
|
+
const parsed = JSON.parse(metadata);
|
|
8574
|
+
return !!parsed && !IsString(parsed);
|
|
8575
|
+
}
|
|
8576
|
+
catch {
|
|
8577
|
+
return false;
|
|
8578
|
+
}
|
|
8247
8579
|
}
|
|
8248
|
-
|
|
8249
|
-
|
|
8580
|
+
/**
|
|
8581
|
+
* Checks if the input is a string.
|
|
8582
|
+
* @param input - any input to check
|
|
8583
|
+
* @returns boolean - true if the input is a string, false otherwise
|
|
8584
|
+
*/
|
|
8585
|
+
function IsString(input) {
|
|
8586
|
+
return typeof input === "string" || input instanceof String;
|
|
8250
8587
|
}
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
|
|
8256
|
-
|
|
8257
|
-
|
|
8258
|
-
|
|
8259
|
-
}
|
|
8260
|
-
|
|
8261
|
-
|
|
8588
|
+
/**
|
|
8589
|
+
* Checks recursively for functions on an object and returns `false` if any are found.
|
|
8590
|
+
* @param o any object, string or number
|
|
8591
|
+
* @returns boolean
|
|
8592
|
+
*/
|
|
8593
|
+
function ObjectCanSafelyStringify(o) {
|
|
8594
|
+
if (typeof o === "function") {
|
|
8595
|
+
return false;
|
|
8596
|
+
}
|
|
8597
|
+
if (o === null || o === true || o === false || typeof o === "number" || IsString(o)) {
|
|
8598
|
+
return true;
|
|
8599
|
+
}
|
|
8600
|
+
if (typeof o === "object") {
|
|
8601
|
+
if (Object.values(o).length === 0) {
|
|
8602
|
+
return true;
|
|
8603
|
+
}
|
|
8604
|
+
return Object.values(o).every((value) => ObjectCanSafelyStringify(value));
|
|
8605
|
+
}
|
|
8606
|
+
if (Array.isArray(o)) {
|
|
8607
|
+
return o.every((value) => ObjectCanSafelyStringify(value));
|
|
8608
|
+
}
|
|
8609
|
+
return false;
|
|
8262
8610
|
}
|
|
8263
|
-
function
|
|
8264
|
-
|
|
8611
|
+
function GetMetadataEntityType(metadata) {
|
|
8612
|
+
if (metadata == null) {
|
|
8613
|
+
return "null";
|
|
8614
|
+
}
|
|
8615
|
+
else if (IsString(metadata)) {
|
|
8616
|
+
return "string";
|
|
8617
|
+
}
|
|
8618
|
+
else if (!ObjectCanSafelyStringify(metadata)) {
|
|
8619
|
+
return "object";
|
|
8620
|
+
}
|
|
8621
|
+
else {
|
|
8622
|
+
return "JSON";
|
|
8623
|
+
}
|
|
8265
8624
|
}
|
|
8266
|
-
function
|
|
8267
|
-
return
|
|
8625
|
+
function HasGltfExtras(metadata) {
|
|
8626
|
+
return IsParsable(metadata) && !!JSON.parse(metadata).gltf;
|
|
8268
8627
|
}
|
|
8269
|
-
function
|
|
8270
|
-
|
|
8271
|
-
|
|
8272
|
-
|
|
8273
|
-
|
|
8274
|
-
|
|
8275
|
-
|
|
8276
|
-
for
|
|
8277
|
-
|
|
8628
|
+
function StringifyMetadata(metadata, format) {
|
|
8629
|
+
if (IsString(metadata)) {
|
|
8630
|
+
return metadata;
|
|
8631
|
+
}
|
|
8632
|
+
if (metadata) {
|
|
8633
|
+
// Try JSON.stringify even for objects with functions — it safely omits
|
|
8634
|
+
// function-valued and undefined properties. Only fall back to String()
|
|
8635
|
+
// for cases that actually throw (e.g. circular references).
|
|
8636
|
+
try {
|
|
8637
|
+
return JSON.stringify(metadata, undefined, format ? PrettyJSONIndent : undefined);
|
|
8278
8638
|
}
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
let root = mesh;
|
|
8282
|
-
while (IsSceneNode(root.parent)) {
|
|
8283
|
-
root = root.parent;
|
|
8639
|
+
catch {
|
|
8640
|
+
return String(metadata);
|
|
8284
8641
|
}
|
|
8285
|
-
addNode(root);
|
|
8286
8642
|
}
|
|
8287
|
-
return
|
|
8643
|
+
return null;
|
|
8288
8644
|
}
|
|
8289
|
-
function
|
|
8290
|
-
|
|
8291
|
-
const nodeSet = new Set(nodes);
|
|
8292
|
-
return nodes.filter((node) => !IsSceneNode(node.parent) || !nodeSet.has(node.parent));
|
|
8645
|
+
function Restringify(value, format) {
|
|
8646
|
+
return IsParsable(value) ? JSON.stringify(JSON.parse(value), undefined, format ? PrettyJSONIndent : undefined) : value;
|
|
8293
8647
|
}
|
|
8294
|
-
function
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
if (parent === ancestor) {
|
|
8298
|
-
return true;
|
|
8299
|
-
}
|
|
8300
|
-
if (!IsSceneNode(parent)) {
|
|
8301
|
-
return false;
|
|
8302
|
-
}
|
|
8303
|
-
parent = parent.parent;
|
|
8648
|
+
function PopulateGLTFExtras(metadata) {
|
|
8649
|
+
if (!metadata) {
|
|
8650
|
+
metadata = "{}";
|
|
8304
8651
|
}
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
function SetVector3Value(target, value) {
|
|
8308
|
-
const x = "x" in value ? value.x : value[0];
|
|
8309
|
-
const y = "x" in value ? value.y : value[1];
|
|
8310
|
-
const z = "x" in value ? value.z : value[2];
|
|
8311
|
-
const observableTarget = target;
|
|
8312
|
-
if (typeof observableTarget.set === "function") {
|
|
8313
|
-
observableTarget.set(x, y, z);
|
|
8652
|
+
if (!IsParsable(metadata)) {
|
|
8653
|
+
return metadata;
|
|
8314
8654
|
}
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8318
|
-
|
|
8655
|
+
try {
|
|
8656
|
+
const parsedJson = JSON.parse(metadata);
|
|
8657
|
+
if (parsedJson) {
|
|
8658
|
+
if (Reflect.has(parsedJson, "gltf")) {
|
|
8659
|
+
if (!Reflect.has(parsedJson.gltf, "extras")) {
|
|
8660
|
+
parsedJson.gltf.extras = {};
|
|
8661
|
+
}
|
|
8662
|
+
}
|
|
8663
|
+
else {
|
|
8664
|
+
parsedJson.gltf = { extras: {} };
|
|
8665
|
+
}
|
|
8666
|
+
}
|
|
8667
|
+
return JSON.stringify(parsedJson);
|
|
8668
|
+
}
|
|
8669
|
+
catch {
|
|
8670
|
+
return metadata;
|
|
8319
8671
|
}
|
|
8320
8672
|
}
|
|
8321
|
-
function
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
const z = "x" in value ? value.z : value[2];
|
|
8325
|
-
const w = "x" in value ? value.w : value[3];
|
|
8326
|
-
const observableTarget = target;
|
|
8327
|
-
if (typeof observableTarget.set === "function") {
|
|
8328
|
-
observableTarget.set(x, y, z, w);
|
|
8673
|
+
function SaveMetadata(entity, metadata) {
|
|
8674
|
+
if (IsParsable(metadata)) {
|
|
8675
|
+
entity.metadata = JSON.parse(metadata);
|
|
8329
8676
|
}
|
|
8330
8677
|
else {
|
|
8331
|
-
|
|
8332
|
-
target.y = y;
|
|
8333
|
-
target.z = z;
|
|
8334
|
-
target.w = w;
|
|
8678
|
+
entity.metadata = metadata;
|
|
8335
8679
|
}
|
|
8336
8680
|
}
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8681
|
+
const useStyles$1 = makeStyles({
|
|
8682
|
+
mainDiv: {
|
|
8683
|
+
display: "flex",
|
|
8684
|
+
flexDirection: "column",
|
|
8685
|
+
gap: tokens.spacingVerticalXS,
|
|
8686
|
+
},
|
|
8687
|
+
buttonDiv: {
|
|
8688
|
+
display: "grid",
|
|
8689
|
+
gridAutoFlow: "column",
|
|
8690
|
+
gridTemplateColumns: "1fr auto auto auto",
|
|
8691
|
+
gap: tokens.spacingHorizontalXS,
|
|
8692
|
+
},
|
|
8693
|
+
});
|
|
8694
|
+
/**
|
|
8695
|
+
* Component to display metadata properties of an entity.
|
|
8696
|
+
* @param props - The properties for the component.
|
|
8697
|
+
* @returns A React component that displays metadata properties.
|
|
8698
|
+
*/
|
|
8699
|
+
const MetadataProperties = (props) => {
|
|
8700
|
+
const { entity } = props;
|
|
8701
|
+
const classes = useStyles$1();
|
|
8702
|
+
const { size } = useContext(ToolContext);
|
|
8703
|
+
const metadata = useProperty(entity, "metadata");
|
|
8704
|
+
const stringifiedMetadata = useMemo(() => StringifyMetadata(metadata, false) ?? "", [metadata]);
|
|
8705
|
+
const metadataType = useMemo(() => GetMetadataEntityType(metadata), [metadata]);
|
|
8706
|
+
const canPreventObjectCorruption = metadataType === "object";
|
|
8707
|
+
const [preventObjectCorruption, setPreventObjectCorruption] = useState(false);
|
|
8708
|
+
const isReadonly = canPreventObjectCorruption && preventObjectCorruption;
|
|
8709
|
+
const [editedMetadata, setEditedMetadata] = useState(stringifiedMetadata);
|
|
8710
|
+
useEffect(() => {
|
|
8711
|
+
setEditedMetadata(stringifiedMetadata);
|
|
8712
|
+
}, [stringifiedMetadata]);
|
|
8713
|
+
const isEditedMetadataJSON = useMemo(() => IsParsable(editedMetadata), [editedMetadata]);
|
|
8714
|
+
const unformattedEditedMetadata = useMemo(() => Restringify(editedMetadata, false), [editedMetadata]);
|
|
8715
|
+
return (jsxs(Fragment, { children: [jsx(TextPropertyLine, { label: "Property Type", value: metadataType }), jsx(Collapse, { visible: canPreventObjectCorruption, children: jsx(SwitchPropertyLine, { label: "Prevent Object Corruption", value: isReadonly, onChange: setPreventObjectCorruption }) }), jsx(LineContainer, { uniqueId: "MetadataTextarea", children: jsx(Textarea, { disabled: isReadonly, value: editedMetadata, onChange: setEditedMetadata }) }), jsx(ButtonLine, { label: "Populate glTF extras", disabled: !!editedMetadata && (!IsParsable(editedMetadata) || HasGltfExtras(editedMetadata)), onClick: () => {
|
|
8716
|
+
const isFormatted = Restringify(editedMetadata, true) === editedMetadata;
|
|
8717
|
+
let withGLTFExtras = PopulateGLTFExtras(editedMetadata);
|
|
8718
|
+
if (isFormatted) {
|
|
8719
|
+
withGLTFExtras = Restringify(withGLTFExtras, true);
|
|
8720
|
+
}
|
|
8721
|
+
setEditedMetadata(withGLTFExtras);
|
|
8722
|
+
} }), jsx(LineContainer, { uniqueId: "MetadataButtonDiv", children: jsxs("div", { className: classes.buttonDiv, children: [jsx(Button$1, { size: size, icon: jsx(SaveRegular, {}), disabled: stringifiedMetadata === unformattedEditedMetadata, onClick: () => SaveMetadata(entity, editedMetadata), children: jsx(Body1, { children: "Save" }) }), jsx(Tooltip$1, { content: "Undo Changes", relationship: "label", children: jsx(Button$1, { size: size, icon: jsx(ArrowUndoRegular, {}), disabled: stringifiedMetadata === unformattedEditedMetadata, onClick: () => setEditedMetadata(stringifiedMetadata) }) }), jsx(Tooltip$1, { content: "Format (Pretty Print)", relationship: "label", children: jsx(Button$1, { size: size, icon: jsx(BracesRegular, {}), disabled: !isEditedMetadataJSON, onClick: () => setEditedMetadata(Restringify(editedMetadata, true)) }) }), jsx(Tooltip$1, { content: "Clear Formatting (Undo Pretty Print)", relationship: "label", children: jsx(Button$1, { size: size, icon: jsx(BracesDismiss16Regular, {}), disabled: !isEditedMetadataJSON, onClick: () => setEditedMetadata(Restringify(editedMetadata, false)) }) })] }) })] }));
|
|
8723
|
+
};
|
|
8724
|
+
|
|
8725
|
+
/**
|
|
8726
|
+
* Gets the distinct animation groups exposed by the inspected engine's registered scenes.
|
|
8727
|
+
* @param engine The engine to inspect.
|
|
8728
|
+
* @returns The animation groups in scene order, without duplicates.
|
|
8729
|
+
*/
|
|
8730
|
+
function GetSceneAnimationGroups(engine) {
|
|
8731
|
+
return [...new Set(GetSceneContexts(engine).flatMap((scene) => scene.animationGroups))];
|
|
8340
8732
|
}
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
|
|
8733
|
+
/**
|
|
8734
|
+
* Tests whether an entity is an animation group in a registered scene.
|
|
8735
|
+
* @param engine The inspected engine.
|
|
8736
|
+
* @param entity The entity to test.
|
|
8737
|
+
* @returns Whether the entity is a reachable animation group.
|
|
8738
|
+
*/
|
|
8739
|
+
function IsAnimationGroup(engine, entity) {
|
|
8740
|
+
return GetSceneAnimationGroups(engine).some((group) => group === entity);
|
|
8741
|
+
}
|
|
8742
|
+
/**
|
|
8743
|
+
* Tests whether an entity is a public target description in a registered scene's animation group.
|
|
8744
|
+
* @param engine The inspected engine.
|
|
8745
|
+
* @param entity The entity to test.
|
|
8746
|
+
* @returns Whether the entity is a reachable targeted animation.
|
|
8747
|
+
*/
|
|
8748
|
+
function IsTargetedAnimation(engine, entity) {
|
|
8749
|
+
return GetSceneAnimationGroups(engine).some((group) => group.targetedAnimations.some((animation) => animation === entity));
|
|
8750
|
+
}
|
|
8751
|
+
/**
|
|
8752
|
+
* Gets animation groups that directly animate an entity or one of a scene node's transform values.
|
|
8753
|
+
* @param engine The inspected engine.
|
|
8754
|
+
* @param entity The entity whose animations should be listed.
|
|
8755
|
+
* @returns Reachable groups with matching public runtime targets.
|
|
8756
|
+
*/
|
|
8757
|
+
function GetEntityAnimationGroups(engine, entity) {
|
|
8758
|
+
return GetSceneAnimationGroups(engine).filter((group) => group.targetedAnimations.some((animation) => animation.target === entity ||
|
|
8759
|
+
(IsSceneNode(entity) &&
|
|
8760
|
+
(animation.target === entity.position ||
|
|
8761
|
+
animation.target === entity.rotationQuaternion ||
|
|
8762
|
+
animation.target === entity.rotation ||
|
|
8763
|
+
animation.target === entity.scaling))));
|
|
8764
|
+
}
|
|
8765
|
+
/**
|
|
8766
|
+
* Gets a display name using the live runtime name when available, without requiring a runtime target.
|
|
8767
|
+
* @param animation The targeted animation.
|
|
8768
|
+
* @returns The target name or node identity and its animated path.
|
|
8769
|
+
*/
|
|
8770
|
+
function GetTargetedAnimationDisplayName(animation) {
|
|
8771
|
+
const target = animation.target;
|
|
8772
|
+
const name = target && "name" in target && typeof target.name === "string" ? target.name : undefined;
|
|
8773
|
+
const targetName = name || animation.targetName || (animation.nodeIndex !== undefined ? `Node ${animation.nodeIndex}` : "Target");
|
|
8774
|
+
return `${targetName}: ${animation.path}`;
|
|
8775
|
+
}
|
|
8776
|
+
/**
|
|
8777
|
+
* Gets the frame rate used by Lite's goToFrame API.
|
|
8778
|
+
* @param group The animation group.
|
|
8779
|
+
* @returns The authored frame rate, or Lite's default of 60 frames per second.
|
|
8780
|
+
*/
|
|
8781
|
+
function GetAnimationFrameRate(group) {
|
|
8782
|
+
return group.frameRate || 60;
|
|
8783
|
+
}
|
|
8784
|
+
/**
|
|
8785
|
+
* Seeks through Lite's public API while preserving whether playback was active.
|
|
8786
|
+
* @param engine The engine used to apply GPU-backed animation poses.
|
|
8787
|
+
* @param group The animation group to seek.
|
|
8788
|
+
* @param frame The requested frame.
|
|
8789
|
+
*/
|
|
8790
|
+
function SeekAnimationFrame(engine, group, frame) {
|
|
8791
|
+
const wasPlaying = group.isPlaying;
|
|
8792
|
+
goToFrame(group, frame, engine);
|
|
8793
|
+
if (wasPlaying) {
|
|
8794
|
+
playAnimation(group);
|
|
8795
|
+
}
|
|
8344
8796
|
}
|
|
8345
8797
|
|
|
8798
|
+
const AnimationGroupControlProperties = MakeLazyComponent(async () => (await import('./animationProperties-BKVw6_ls.js')).AnimationGroupControlProperties);
|
|
8799
|
+
const AnimationGroupInfoProperties = MakeLazyComponent(async () => (await import('./animationProperties-BKVw6_ls.js')).AnimationGroupInfoProperties);
|
|
8800
|
+
const TargetedAnimationProperties = MakeLazyComponent(async () => (await import('./animationProperties-BKVw6_ls.js')).TargetedAnimationProperties);
|
|
8801
|
+
const EntityAnimationProperties = MakeLazyComponent(async () => (await import('./animationProperties-BKVw6_ls.js')).EntityAnimationProperties);
|
|
8802
|
+
const AnimationPropertiesServiceDefinition = {
|
|
8803
|
+
friendlyName: "Babylon Lite Animation Properties",
|
|
8804
|
+
consumes: [PropertiesServiceIdentity, EngineContextIdentity, SelectionServiceIdentity],
|
|
8805
|
+
factory: (propertiesService, engineContext, selectionService) => {
|
|
8806
|
+
const engine = engineContext.engine;
|
|
8807
|
+
const groupRegistration = propertiesService.addSectionContent({
|
|
8808
|
+
key: "Babylon Lite Animation Group Properties",
|
|
8809
|
+
predicate: (entity) => IsAnimationGroup(engine, entity),
|
|
8810
|
+
content: [
|
|
8811
|
+
{
|
|
8812
|
+
section: "Control",
|
|
8813
|
+
component: ({ context }) => jsx(AnimationGroupControlProperties, { engine: engine, group: context }),
|
|
8814
|
+
},
|
|
8815
|
+
{
|
|
8816
|
+
section: "Info",
|
|
8817
|
+
component: ({ context }) => jsx(AnimationGroupInfoProperties, { group: context }),
|
|
8818
|
+
},
|
|
8819
|
+
{
|
|
8820
|
+
section: "Metadata",
|
|
8821
|
+
component: ({ context }) => jsx(MetadataProperties, { entity: context }),
|
|
8822
|
+
},
|
|
8823
|
+
],
|
|
8824
|
+
});
|
|
8825
|
+
const targetedAnimationRegistration = propertiesService.addSectionContent({
|
|
8826
|
+
key: "Babylon Lite Targeted Animation Properties",
|
|
8827
|
+
predicate: (entity) => IsTargetedAnimation(engine, entity),
|
|
8828
|
+
content: [
|
|
8829
|
+
{
|
|
8830
|
+
section: "General",
|
|
8831
|
+
component: ({ context }) => jsx(TargetedAnimationProperties, { animation: context, selectionService: selectionService }),
|
|
8832
|
+
},
|
|
8833
|
+
],
|
|
8834
|
+
});
|
|
8835
|
+
const entityRegistration = propertiesService.addSectionContent({
|
|
8836
|
+
key: "Babylon Lite Entity Animation Properties",
|
|
8837
|
+
predicate: (entity) => typeof entity === "object" && entity !== null && !IsAnimationGroup(engine, entity) && !IsTargetedAnimation(engine, entity),
|
|
8838
|
+
content: [
|
|
8839
|
+
{
|
|
8840
|
+
section: "Animation",
|
|
8841
|
+
component: ({ context }) => jsx(EntityAnimationProperties, { engine: engine, entity: context, selectionService: selectionService }),
|
|
8842
|
+
},
|
|
8843
|
+
],
|
|
8844
|
+
});
|
|
8845
|
+
return {
|
|
8846
|
+
dispose: () => {
|
|
8847
|
+
entityRegistration.dispose();
|
|
8848
|
+
targetedAnimationRegistration.dispose();
|
|
8849
|
+
groupRegistration.dispose();
|
|
8850
|
+
},
|
|
8851
|
+
};
|
|
8852
|
+
},
|
|
8853
|
+
};
|
|
8854
|
+
|
|
8346
8855
|
/**
|
|
8347
8856
|
* Runtime-neutral controlled editor for two-, three-, and four-component numeric values.
|
|
8348
8857
|
* @param props The value, change callback, component adapter, and property-line presentation.
|
|
@@ -8363,11 +8872,11 @@ const ControlledTensorPropertyLine = (props) => {
|
|
|
8363
8872
|
props.onChange(newValue);
|
|
8364
8873
|
};
|
|
8365
8874
|
const summary = adapter.components.map((component) => formatted(adapter.getComponent(props.value, component))).join(", ");
|
|
8366
|
-
return (jsx(PropertyLine, { ...props, expandedContent: jsxs(Fragment, { children: [props.expandedContent, jsx(TensorSliders, { value: value, adapter: adapter, min: min, max: max, unit: unit, step: step, precision: precision, converted: converted, onChange: onComponentChange })] }), children: jsx(Body1, { children: `[${summary}]` }) }));
|
|
8875
|
+
return (jsx(PropertyLine, { ...props, expandedContent: jsxs(Fragment, { children: [props.expandedContent, jsx(TensorSliders, { value: value, adapter: adapter, min: min, max: max, unit: unit, step: step, precision: precision, disabled: props.disabled, converted: converted, onChange: onComponentChange })] }), children: jsx(Body1, { children: `[${summary}]` }) }));
|
|
8367
8876
|
};
|
|
8368
8877
|
const TensorSliders = (props) => {
|
|
8369
|
-
const { value, adapter, min, max, unit, step, precision, converted, onChange } = props;
|
|
8370
|
-
return (jsx(Fragment, { children: adapter.components.map((component) => (jsx(NumberInputPropertyLine, { label: component.toUpperCase(), value: converted(adapter.getComponent(value, component)), min: min, max: max, onChange: (componentValue) => onChange(componentValue, component), unit: unit, step: step, precision: precision }, component))) }));
|
|
8878
|
+
const { value, adapter, min, max, unit, step, precision, disabled, converted, onChange } = props;
|
|
8879
|
+
return (jsx(Fragment, { children: adapter.components.map((component) => (jsx(NumberInputPropertyLine, { label: component.toUpperCase(), value: converted(adapter.getComponent(value, component)), min: min, max: max, onChange: (componentValue) => onChange(componentValue, component), unit: unit, step: step, precision: precision, disabled: disabled }, component))) }));
|
|
8371
8880
|
};
|
|
8372
8881
|
const RadiansToDegreesConverter = {
|
|
8373
8882
|
from: (value) => (value * 180) / Math.PI,
|
|
@@ -8419,6 +8928,11 @@ function GetComponent(value, component) {
|
|
|
8419
8928
|
return "w" in value ? value.w : 0;
|
|
8420
8929
|
}
|
|
8421
8930
|
}
|
|
8931
|
+
const Vector2Adapter = {
|
|
8932
|
+
components: ["x", "y"],
|
|
8933
|
+
getComponent: GetComponent,
|
|
8934
|
+
withComponent: (value, component, componentValue) => IsNumberTuple(value) ? [component === "x" ? componentValue : value[0], component === "y" ? componentValue : value[1]] : { ...value, [component]: componentValue },
|
|
8935
|
+
};
|
|
8422
8936
|
const Vector3Adapter = {
|
|
8423
8937
|
components: ["x", "y", "z"],
|
|
8424
8938
|
getComponent: GetComponent,
|
|
@@ -8426,6 +8940,18 @@ const Vector3Adapter = {
|
|
|
8426
8940
|
? [component === "x" ? componentValue : value[0], component === "y" ? componentValue : value[1], component === "z" ? componentValue : value[2]]
|
|
8427
8941
|
: { ...value, [component]: componentValue },
|
|
8428
8942
|
};
|
|
8943
|
+
const Vector4Adapter = {
|
|
8944
|
+
components: ["x", "y", "z", "w"],
|
|
8945
|
+
getComponent: GetComponent,
|
|
8946
|
+
withComponent: (value, component, componentValue) => IsNumberTuple(value)
|
|
8947
|
+
? [
|
|
8948
|
+
component === "x" ? componentValue : value[0],
|
|
8949
|
+
component === "y" ? componentValue : value[1],
|
|
8950
|
+
component === "z" ? componentValue : value[2],
|
|
8951
|
+
component === "w" ? componentValue : value[3],
|
|
8952
|
+
]
|
|
8953
|
+
: { ...value, [component]: componentValue },
|
|
8954
|
+
};
|
|
8429
8955
|
const QuaternionTensorAdapter = {
|
|
8430
8956
|
components: ["x", "y", "z", "w"],
|
|
8431
8957
|
getComponent: GetComponent,
|
|
@@ -8446,7 +8972,7 @@ const QuaternionTensorAdapter = {
|
|
|
8446
8972
|
*/
|
|
8447
8973
|
function CreateQuaternionFromEuler(value, source) {
|
|
8448
8974
|
const [x, y, z] = "x" in value ? [value.x, value.y, value.z] : value;
|
|
8449
|
-
const quaternion =
|
|
8975
|
+
const quaternion = eulerXYZToQuatTuple(x, y, z);
|
|
8450
8976
|
return "x" in source ? { x: quaternion[0], y: quaternion[1], z: quaternion[2], w: quaternion[3] } : quaternion;
|
|
8451
8977
|
}
|
|
8452
8978
|
const QuaternionAdapter = {
|
|
@@ -8455,10 +8981,12 @@ const QuaternionAdapter = {
|
|
|
8455
8981
|
fromEuler: CreateQuaternionFromEuler,
|
|
8456
8982
|
toEuler: (value) => {
|
|
8457
8983
|
const [x, y, z, w] = "x" in value ? [value.x, value.y, value.z, value.w] : value;
|
|
8458
|
-
return
|
|
8984
|
+
return quatToEulerXYZTuple(x, y, z, w);
|
|
8459
8985
|
},
|
|
8460
8986
|
};
|
|
8987
|
+
const Vector2PropertyLine = (props) => jsx(ControlledTensorPropertyLine, { ...props, adapter: Vector2Adapter });
|
|
8461
8988
|
const Vector3PropertyLine = (props) => jsx(ControlledTensorPropertyLine, { ...props, adapter: Vector3Adapter });
|
|
8989
|
+
const Vector4PropertyLine = (props) => jsx(ControlledTensorPropertyLine, { ...props, adapter: Vector4Adapter });
|
|
8462
8990
|
const QuaternionPropertyLine = (props) => jsx(ControlledQuaternionPropertyLine, { ...props, adapter: QuaternionAdapter });
|
|
8463
8991
|
|
|
8464
8992
|
function GetPosition$2(camera) {
|
|
@@ -8555,7 +9083,7 @@ const ControlledColorPropertyLine = (props) => {
|
|
|
8555
9083
|
}, currentValue));
|
|
8556
9084
|
};
|
|
8557
9085
|
const color = adapter.getColor(currentValue);
|
|
8558
|
-
return (jsx(PropertyLine, { ref: propertyLineRef, ...props, expandedContent: jsx(ColorSliders, { color: color, onSliderChange: onSliderChange }), children: createElement(adapter.picker, {
|
|
9086
|
+
return (jsx(PropertyLine, { ref: propertyLineRef, ...props, expandedContent: jsx(ColorSliders, { color: color, onSliderChange: onSliderChange, disabled: props.disabled }), children: createElement(adapter.picker, {
|
|
8559
9087
|
value: currentValue,
|
|
8560
9088
|
onChange: handleChange,
|
|
8561
9089
|
isLinearMode: props.isLinearMode,
|
|
@@ -8566,11 +9094,11 @@ const ControlledColorPropertyLine = (props) => {
|
|
|
8566
9094
|
}) }));
|
|
8567
9095
|
};
|
|
8568
9096
|
const ColorSliders = (props) => {
|
|
8569
|
-
const { color, onSliderChange } = props;
|
|
8570
|
-
return (jsxs(Fragment, { children: [jsx(SyncedSliderPropertyLine, { label: "R", value: color.r * 255, min: 0, max: 255, onChange: (value) => onSliderChange(value, "r") }), jsx(SyncedSliderPropertyLine, { label: "G", value: color.g * 255, min: 0, max: 255, onChange: (value) => onSliderChange(value, "g") }), jsx(SyncedSliderPropertyLine, { label: "B", value: color.b * 255, min: 0, max: 255, onChange: (value) => onSliderChange(value, "b") }), color.a === undefined ? undefined : (jsx(SyncedSliderPropertyLine, { label: "A", value: color.a, min: 0, max: 1, step: 0.01, onChange: (value) => onSliderChange(value, "a") }))] }));
|
|
9097
|
+
const { color, disabled, onSliderChange } = props;
|
|
9098
|
+
return (jsxs(Fragment, { children: [jsx(SyncedSliderPropertyLine, { label: "R", value: color.r * 255, min: 0, max: 255, disabled: disabled, onChange: (value) => onSliderChange(value, "r") }), jsx(SyncedSliderPropertyLine, { label: "G", value: color.g * 255, min: 0, max: 255, disabled: disabled, onChange: (value) => onSliderChange(value, "g") }), jsx(SyncedSliderPropertyLine, { label: "B", value: color.b * 255, min: 0, max: 255, disabled: disabled, onChange: (value) => onSliderChange(value, "b") }), color.a === undefined ? undefined : (jsx(SyncedSliderPropertyLine, { label: "A", value: color.a, min: 0, max: 1, step: 0.01, disabled: disabled, onChange: (value) => onSliderChange(value, "a") }))] }));
|
|
8571
9099
|
};
|
|
8572
9100
|
|
|
8573
|
-
const useStyles
|
|
9101
|
+
const useStyles = makeStyles({
|
|
8574
9102
|
picker: {
|
|
8575
9103
|
width: "350px",
|
|
8576
9104
|
height: "350px",
|
|
@@ -8669,7 +9197,7 @@ function ColorToHex(color) {
|
|
|
8669
9197
|
*/
|
|
8670
9198
|
const StructuralColorPickerPopup = (props) => {
|
|
8671
9199
|
const { value, onChange, adapter, isLinearMode, ...rest } = props;
|
|
8672
|
-
const classes = useStyles
|
|
9200
|
+
const classes = useStyles();
|
|
8673
9201
|
const { size } = useContext(ToolContext);
|
|
8674
9202
|
const [currentValue, setCurrentValue] = useState(value);
|
|
8675
9203
|
useEffect(() => {
|
|
@@ -8733,6 +9261,7 @@ const Adapter = {
|
|
|
8733
9261
|
createColor: (color, source) => (IsColor4Value(source) ? CreateColor4Value(color, source) : CreateColor3Value(color, source)),
|
|
8734
9262
|
};
|
|
8735
9263
|
const Color3PropertyLine = (props) => (jsx(ControlledColorPropertyLine, { ...props, adapter: Adapter }));
|
|
9264
|
+
const Color4PropertyLine = (props) => (jsx(ControlledColorPropertyLine, { ...props, adapter: Adapter }));
|
|
8736
9265
|
|
|
8737
9266
|
function GetVector3(value) {
|
|
8738
9267
|
return [value.x, value.y, value.z];
|
|
@@ -8857,28 +9386,598 @@ const LightPropertiesServiceDefinition = {
|
|
|
8857
9386
|
},
|
|
8858
9387
|
};
|
|
8859
9388
|
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
|
|
8863
|
-
|
|
8864
|
-
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
|
|
8871
|
-
|
|
8872
|
-
|
|
8873
|
-
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
|
|
8878
|
-
|
|
8879
|
-
|
|
8880
|
-
|
|
8881
|
-
|
|
9389
|
+
/**
|
|
9390
|
+
* Returns scenes that still contain the selected material, rather than just another view of its source.
|
|
9391
|
+
* @param record The indexed source record.
|
|
9392
|
+
* @param material The selected source or view.
|
|
9393
|
+
* @returns Scenes with a live mesh referencing the selected material.
|
|
9394
|
+
*/
|
|
9395
|
+
function GetMaterialOwningScenes(record, material) {
|
|
9396
|
+
return record.scenes.filter((scene) => Array.isArray(scene.meshes) &&
|
|
9397
|
+
scene.meshes.some((mesh) => mesh?.material && (material === record.source ? getMaterialSource(mesh.material) === record.source : mesh.material === material)));
|
|
9398
|
+
}
|
|
9399
|
+
|
|
9400
|
+
function Add(bindings, id, entity) {
|
|
9401
|
+
if (entity) {
|
|
9402
|
+
bindings.push({ id, entity });
|
|
9403
|
+
}
|
|
9404
|
+
}
|
|
9405
|
+
function GetStandardBindings(material) {
|
|
9406
|
+
const bindings = [];
|
|
9407
|
+
Add(bindings, "standard.diffuse", material.diffuseTexture);
|
|
9408
|
+
Add(bindings, "standard.emissive", getStandardEmissiveTexture(material));
|
|
9409
|
+
Add(bindings, "standard.bump", getStandardBumpTexture(material));
|
|
9410
|
+
Add(bindings, "standard.specular", getStandardSpecularTexture(material));
|
|
9411
|
+
Add(bindings, "standard.ambient", getStandardAmbientTexture(material));
|
|
9412
|
+
Add(bindings, "standard.lightmap", getStandardLightmapTexture(material));
|
|
9413
|
+
Add(bindings, "standard.opacity", getStandardOpacityTexture(material));
|
|
9414
|
+
Add(bindings, "standard.reflection2d", getStandardReflectionTexture(material));
|
|
9415
|
+
Add(bindings, "standard.reflectionCube", getStandardReflectionCubeTexture(material));
|
|
9416
|
+
return bindings;
|
|
9417
|
+
}
|
|
9418
|
+
function GetPbrBindings(material) {
|
|
9419
|
+
const bindings = [];
|
|
9420
|
+
Add(bindings, "pbr.baseColor", material.baseColorTexture);
|
|
9421
|
+
Add(bindings, "pbr.normal", material.normalTexture);
|
|
9422
|
+
Add(bindings, "pbr.orm", material.ormTexture);
|
|
9423
|
+
Add(bindings, "pbr.occlusion", material.occlusionTexture);
|
|
9424
|
+
Add(bindings, "pbr.emissive", material.emissiveTexture);
|
|
9425
|
+
Add(bindings, "pbr.specGloss", material.specGlossTexture);
|
|
9426
|
+
Add(bindings, "pbr.lightmap", material.lightmapTexture);
|
|
9427
|
+
const metallicReflectance = getPbrMetallicReflectance(material);
|
|
9428
|
+
Add(bindings, "pbr.metallicReflectance", metallicReflectance?.texture);
|
|
9429
|
+
Add(bindings, "pbr.reflectance", metallicReflectance?.reflectanceTexture);
|
|
9430
|
+
const clearCoat = getPbrClearCoat(material);
|
|
9431
|
+
Add(bindings, "pbr.clearCoat", clearCoat?.texture);
|
|
9432
|
+
Add(bindings, "pbr.clearCoatRoughness", clearCoat?.roughnessTexture);
|
|
9433
|
+
Add(bindings, "pbr.clearCoatBump", clearCoat?.bumpTexture);
|
|
9434
|
+
const sheen = getPbrSheen(material);
|
|
9435
|
+
Add(bindings, "pbr.sheen", sheen?.texture);
|
|
9436
|
+
Add(bindings, "pbr.sheenRoughness", sheen?.roughnessTexture);
|
|
9437
|
+
const iridescence = getPbrIridescence(material);
|
|
9438
|
+
Add(bindings, "pbr.iridescence", iridescence?.texture);
|
|
9439
|
+
Add(bindings, "pbr.iridescenceThickness", iridescence?.thicknessTexture);
|
|
9440
|
+
Add(bindings, "pbr.anisotropy", getPbrAnisotropy(material)?.texture);
|
|
9441
|
+
const subsurface = getPbrSubsurface(material);
|
|
9442
|
+
Add(bindings, "pbr.translucencyColor", subsurface?.translucency?.colorTexture);
|
|
9443
|
+
Add(bindings, "pbr.translucencyIntensity", subsurface?.translucency?.intensityTexture);
|
|
9444
|
+
Add(bindings, "pbr.thickness", subsurface?.thickness?.texture);
|
|
9445
|
+
Add(bindings, "pbr.transmission", getPbrTransmission(material)?.texture);
|
|
9446
|
+
return bindings;
|
|
9447
|
+
}
|
|
9448
|
+
function GetShaderBindings(material) {
|
|
9449
|
+
const bindings = [];
|
|
9450
|
+
for (const declaration of material.samplerDecls) {
|
|
9451
|
+
Add(bindings, `shader.sampler:${declaration.name}`, getShaderTexture(material, declaration.name));
|
|
9452
|
+
}
|
|
9453
|
+
return bindings;
|
|
9454
|
+
}
|
|
9455
|
+
function GetNodeBindings(material) {
|
|
9456
|
+
const bindings = [];
|
|
9457
|
+
for (const [name, input] of Object.entries(material.inputs)) {
|
|
9458
|
+
if (input.type === "texture2d") {
|
|
9459
|
+
Add(bindings, `node.texture:${name}`, input.texture);
|
|
9460
|
+
}
|
|
9461
|
+
}
|
|
9462
|
+
return bindings;
|
|
9463
|
+
}
|
|
9464
|
+
/**
|
|
9465
|
+
* Builds canonical topology edges without retaining any UI descriptor implementation.
|
|
9466
|
+
* @param material The exact source material.
|
|
9467
|
+
* @returns Texture edges in canonical family order.
|
|
9468
|
+
* @internal
|
|
9469
|
+
*/
|
|
9470
|
+
function GetMaterialTopologyBindings(material) {
|
|
9471
|
+
switch (getMaterialFamily(material)) {
|
|
9472
|
+
case "standard":
|
|
9473
|
+
return GetStandardBindings(material);
|
|
9474
|
+
case "pbr":
|
|
9475
|
+
return GetPbrBindings(material);
|
|
9476
|
+
case "shader":
|
|
9477
|
+
return GetShaderBindings(material);
|
|
9478
|
+
case "node":
|
|
9479
|
+
return GetNodeBindings(material);
|
|
9480
|
+
default:
|
|
9481
|
+
return [];
|
|
9482
|
+
}
|
|
9483
|
+
}
|
|
9484
|
+
|
|
9485
|
+
function IsObject(value) {
|
|
9486
|
+
return typeof value === "object" && value !== null;
|
|
9487
|
+
}
|
|
9488
|
+
function GetSceneMaterials(scene) {
|
|
9489
|
+
const sources = new Set();
|
|
9490
|
+
const materials = [];
|
|
9491
|
+
const views = new Set();
|
|
9492
|
+
if (!Array.isArray(scene.meshes)) {
|
|
9493
|
+
return { sources: materials, views: [] };
|
|
9494
|
+
}
|
|
9495
|
+
for (const mesh of scene.meshes) {
|
|
9496
|
+
if (!IsObject(mesh) || !IsObject(mesh.material)) {
|
|
9497
|
+
continue;
|
|
9498
|
+
}
|
|
9499
|
+
try {
|
|
9500
|
+
const source = getMaterialSource(mesh.material);
|
|
9501
|
+
if (!sources.has(source)) {
|
|
9502
|
+
sources.add(source);
|
|
9503
|
+
materials.push(source);
|
|
9504
|
+
}
|
|
9505
|
+
if (mesh.material !== source) {
|
|
9506
|
+
views.add(mesh.material);
|
|
9507
|
+
}
|
|
9508
|
+
}
|
|
9509
|
+
catch {
|
|
9510
|
+
// Stale or malformed materials are omitted until a later topology update.
|
|
9511
|
+
}
|
|
9512
|
+
}
|
|
9513
|
+
return { sources: materials, views: [...views] };
|
|
9514
|
+
}
|
|
9515
|
+
function AppendTextureState(snapshot, texture) {
|
|
9516
|
+
try {
|
|
9517
|
+
const metadata = getTextureMetadata(texture);
|
|
9518
|
+
if (!metadata) {
|
|
9519
|
+
snapshot.push("stale-texture");
|
|
9520
|
+
return;
|
|
9521
|
+
}
|
|
9522
|
+
const texture2d = texture;
|
|
9523
|
+
snapshot.push(metadata.kind, metadata.name, metadata.origin, metadata.width, metadata.height, metadata.layers, metadata.depth, metadata.format, metadata.mipLevelCount, metadata.sampleType, metadata.colorSpace, metadata.invertY, metadata.sampler?.addressModeU, metadata.sampler?.addressModeV, metadata.sampler?.addressModeW, metadata.sampler?.minFilter, metadata.sampler?.magFilter, metadata.sampler?.mipmapFilter, metadata.sampler?.maxAnisotropy, metadata.capabilities.renderAttachment, metadata.capabilities.dynamicUpdate, metadata.capabilities.sampledDepth, getTextureCoordinateIndex(texture2d), hasTextureTransform(texture2d));
|
|
9524
|
+
if (hasTextureTransform(texture2d)) {
|
|
9525
|
+
const transform = getTextureTransform(texture2d);
|
|
9526
|
+
snapshot.push(transform?.uOffset, transform?.vOffset, transform?.uScale, transform?.vScale, transform?.uAng);
|
|
9527
|
+
}
|
|
9528
|
+
}
|
|
9529
|
+
catch {
|
|
9530
|
+
snapshot.push("stale-texture");
|
|
9531
|
+
}
|
|
9532
|
+
}
|
|
9533
|
+
function AppendMaterialStructure(snapshot, material, family) {
|
|
9534
|
+
if (family === "node") {
|
|
9535
|
+
const inputs = Object.entries(material.inputs);
|
|
9536
|
+
snapshot.push(inputs.length);
|
|
9537
|
+
for (const [name, input] of inputs) {
|
|
9538
|
+
snapshot.push(name, input.type);
|
|
9539
|
+
}
|
|
9540
|
+
}
|
|
9541
|
+
else if (family === "shader") {
|
|
9542
|
+
const shader = material;
|
|
9543
|
+
snapshot.push(shader.attributes.length, ...shader.attributes, shader.uniformDecls.length);
|
|
9544
|
+
for (const declaration of shader.uniformDecls) {
|
|
9545
|
+
snapshot.push(declaration.name, declaration.type);
|
|
9546
|
+
}
|
|
9547
|
+
snapshot.push(shader.samplerDecls.length);
|
|
9548
|
+
for (const declaration of shader.samplerDecls) {
|
|
9549
|
+
snapshot.push(declaration.name, declaration.sampleType, declaration.viewDimension, declaration.comparison);
|
|
9550
|
+
}
|
|
9551
|
+
snapshot.push(shader.storageBufferDecls.length);
|
|
9552
|
+
for (const declaration of shader.storageBufferDecls) {
|
|
9553
|
+
snapshot.push(declaration.name, declaration.type);
|
|
9554
|
+
}
|
|
9555
|
+
snapshot.push(shader.defines.length);
|
|
9556
|
+
for (const define of shader.defines) {
|
|
9557
|
+
snapshot.push(define.name, define.value);
|
|
9558
|
+
}
|
|
9559
|
+
}
|
|
9560
|
+
else if (family === "pbr") {
|
|
9561
|
+
const pbr = material;
|
|
9562
|
+
const subsurface = getPbrSubsurface(pbr);
|
|
9563
|
+
snapshot.push(!!getPbrMetallicReflectance(pbr), !!getPbrClearCoat(pbr), !!getPbrSheen(pbr), !!getPbrIridescence(pbr), !!getPbrAnisotropy(pbr), !!subsurface, !!subsurface?.translucency, !!subsurface?.thickness, !!getPbrTransmission(pbr));
|
|
9564
|
+
}
|
|
9565
|
+
}
|
|
9566
|
+
/**
|
|
9567
|
+
* Maintains deterministic, Inspector-owned resource records for one Lite engine.
|
|
9568
|
+
* @internal
|
|
9569
|
+
*/
|
|
9570
|
+
class SceneResourceIndex {
|
|
9571
|
+
constructor(_engine) {
|
|
9572
|
+
this._engine = _engine;
|
|
9573
|
+
this._sceneSnapshots = new Map();
|
|
9574
|
+
this._materialRecords = new Map();
|
|
9575
|
+
this._textureRecords = new Map();
|
|
9576
|
+
this._textureOrdinals = new WeakMap();
|
|
9577
|
+
this._nextTextureOrdinal = 1;
|
|
9578
|
+
this.refresh();
|
|
9579
|
+
}
|
|
9580
|
+
/** Rebuilds the resource topology from current public scene and binding state. */
|
|
9581
|
+
refresh() {
|
|
9582
|
+
const scenes = this._getScenes();
|
|
9583
|
+
const sceneMaterials = new Map();
|
|
9584
|
+
const sceneViews = new Map();
|
|
9585
|
+
const materialDrafts = new Map();
|
|
9586
|
+
for (const scene of scenes) {
|
|
9587
|
+
const { sources, views } = GetSceneMaterials(scene);
|
|
9588
|
+
sceneMaterials.set(scene, sources);
|
|
9589
|
+
sceneViews.set(scene, views);
|
|
9590
|
+
for (const source of sources) {
|
|
9591
|
+
let draft = materialDrafts.get(source);
|
|
9592
|
+
if (!draft) {
|
|
9593
|
+
draft = {
|
|
9594
|
+
source,
|
|
9595
|
+
family: getMaterialFamily(source),
|
|
9596
|
+
displayName: source.name || "Material",
|
|
9597
|
+
scenes: [],
|
|
9598
|
+
bindings: GetMaterialTopologyBindings(source),
|
|
9599
|
+
};
|
|
9600
|
+
materialDrafts.set(source, draft);
|
|
9601
|
+
}
|
|
9602
|
+
draft.scenes.push(scene);
|
|
9603
|
+
}
|
|
9604
|
+
}
|
|
9605
|
+
const materialRecords = new Map();
|
|
9606
|
+
for (const draft of materialDrafts.values()) {
|
|
9607
|
+
materialRecords.set(draft.source, draft);
|
|
9608
|
+
}
|
|
9609
|
+
const viewBindings = new Map();
|
|
9610
|
+
for (const views of sceneViews.values()) {
|
|
9611
|
+
for (const view of views) {
|
|
9612
|
+
if (viewBindings.has(view)) {
|
|
9613
|
+
continue;
|
|
9614
|
+
}
|
|
9615
|
+
const sourceBindings = materialRecords.get(getMaterialSource(view))?.bindings ?? [];
|
|
9616
|
+
viewBindings.set(view, GetMaterialTopologyBindings(view).filter((binding) => sourceBindings.find((candidate) => candidate.id === binding.id)?.entity !== binding.entity));
|
|
9617
|
+
}
|
|
9618
|
+
}
|
|
9619
|
+
const textureDrafts = new Map();
|
|
9620
|
+
const addBindings = (material, bindings) => {
|
|
9621
|
+
for (const binding of bindings) {
|
|
9622
|
+
let texture = textureDrafts.get(binding.entity);
|
|
9623
|
+
if (!texture) {
|
|
9624
|
+
try {
|
|
9625
|
+
const metadata = getTextureMetadata(binding.entity);
|
|
9626
|
+
if (!metadata) {
|
|
9627
|
+
continue;
|
|
9628
|
+
}
|
|
9629
|
+
texture = {
|
|
9630
|
+
entity: binding.entity,
|
|
9631
|
+
metadata,
|
|
9632
|
+
ordinal: this._getTextureOrdinal(binding.entity),
|
|
9633
|
+
consumers: [],
|
|
9634
|
+
};
|
|
9635
|
+
}
|
|
9636
|
+
catch {
|
|
9637
|
+
continue;
|
|
9638
|
+
}
|
|
9639
|
+
textureDrafts.set(binding.entity, texture);
|
|
9640
|
+
}
|
|
9641
|
+
texture.consumers.push({ material, bindingId: binding.id });
|
|
9642
|
+
}
|
|
9643
|
+
};
|
|
9644
|
+
for (const material of materialRecords.values()) {
|
|
9645
|
+
addBindings(material.source, material.bindings);
|
|
9646
|
+
}
|
|
9647
|
+
for (const [view, bindings] of viewBindings) {
|
|
9648
|
+
addBindings(view, bindings);
|
|
9649
|
+
}
|
|
9650
|
+
const textureRecords = new Map();
|
|
9651
|
+
for (const draft of textureDrafts.values()) {
|
|
9652
|
+
textureRecords.set(draft.entity, draft);
|
|
9653
|
+
}
|
|
9654
|
+
const sceneSnapshots = new Map();
|
|
9655
|
+
for (const scene of scenes) {
|
|
9656
|
+
const materials = (sceneMaterials.get(scene) ?? []).flatMap((source) => {
|
|
9657
|
+
const record = materialRecords.get(source);
|
|
9658
|
+
return record ? [record] : [];
|
|
9659
|
+
});
|
|
9660
|
+
const seenTextures = new Set();
|
|
9661
|
+
const textures = [];
|
|
9662
|
+
for (const material of materials) {
|
|
9663
|
+
for (const binding of material.bindings) {
|
|
9664
|
+
const record = textureRecords.get(binding.entity);
|
|
9665
|
+
if (record && !seenTextures.has(binding.entity)) {
|
|
9666
|
+
seenTextures.add(binding.entity);
|
|
9667
|
+
textures.push(record);
|
|
9668
|
+
}
|
|
9669
|
+
}
|
|
9670
|
+
}
|
|
9671
|
+
for (const view of sceneViews.get(scene) ?? []) {
|
|
9672
|
+
for (const binding of viewBindings.get(view) ?? []) {
|
|
9673
|
+
const record = textureRecords.get(binding.entity);
|
|
9674
|
+
if (record && !seenTextures.has(binding.entity)) {
|
|
9675
|
+
seenTextures.add(binding.entity);
|
|
9676
|
+
textures.push(record);
|
|
9677
|
+
}
|
|
9678
|
+
}
|
|
9679
|
+
}
|
|
9680
|
+
sceneSnapshots.set(scene, { scene, materials, textures });
|
|
9681
|
+
}
|
|
9682
|
+
this._sceneSnapshots = sceneSnapshots;
|
|
9683
|
+
this._materialRecords = materialRecords;
|
|
9684
|
+
this._textureRecords = textureRecords;
|
|
9685
|
+
}
|
|
9686
|
+
/**
|
|
9687
|
+
* Captures the public identities and values that drive index and Properties refresh.
|
|
9688
|
+
* @returns A deterministic topology snapshot.
|
|
9689
|
+
*/
|
|
9690
|
+
getTopologySnapshot() {
|
|
9691
|
+
const snapshot = [];
|
|
9692
|
+
const seenMaterials = new Set();
|
|
9693
|
+
const seenTextures = new Set();
|
|
9694
|
+
const appendMaterial = (material) => {
|
|
9695
|
+
if (seenMaterials.has(material)) {
|
|
9696
|
+
return;
|
|
9697
|
+
}
|
|
9698
|
+
seenMaterials.add(material);
|
|
9699
|
+
const family = getMaterialFamily(material);
|
|
9700
|
+
const bindings = GetMaterialTopologyBindings(material);
|
|
9701
|
+
snapshot.push(family, material.name, bindings.length);
|
|
9702
|
+
AppendMaterialStructure(snapshot, material, family);
|
|
9703
|
+
for (const binding of bindings) {
|
|
9704
|
+
snapshot.push(binding.id, binding.entity);
|
|
9705
|
+
if (!seenTextures.has(binding.entity)) {
|
|
9706
|
+
seenTextures.add(binding.entity);
|
|
9707
|
+
AppendTextureState(snapshot, binding.entity);
|
|
9708
|
+
}
|
|
9709
|
+
}
|
|
9710
|
+
};
|
|
9711
|
+
for (const surface of this._engine.surfaces) {
|
|
9712
|
+
snapshot.push(surface);
|
|
9713
|
+
for (const context of getRenderingContexts(surface)) {
|
|
9714
|
+
snapshot.push(context);
|
|
9715
|
+
if (getRenderingContextKind(context) !== "scene") {
|
|
9716
|
+
continue;
|
|
9717
|
+
}
|
|
9718
|
+
const scene = context;
|
|
9719
|
+
if (!Array.isArray(scene.meshes)) {
|
|
9720
|
+
snapshot.push("invalid-meshes");
|
|
9721
|
+
continue;
|
|
9722
|
+
}
|
|
9723
|
+
snapshot.push(scene.meshes.length);
|
|
9724
|
+
for (const mesh of scene.meshes) {
|
|
9725
|
+
snapshot.push(mesh);
|
|
9726
|
+
if (!IsObject(mesh) || !IsObject(mesh.material)) {
|
|
9727
|
+
snapshot.push(mesh?.material);
|
|
9728
|
+
continue;
|
|
9729
|
+
}
|
|
9730
|
+
try {
|
|
9731
|
+
const source = getMaterialSource(mesh.material);
|
|
9732
|
+
snapshot.push(mesh.material, source);
|
|
9733
|
+
appendMaterial(source);
|
|
9734
|
+
if (mesh.material !== source) {
|
|
9735
|
+
appendMaterial(mesh.material);
|
|
9736
|
+
}
|
|
9737
|
+
}
|
|
9738
|
+
catch {
|
|
9739
|
+
snapshot.push("stale-material");
|
|
9740
|
+
}
|
|
9741
|
+
}
|
|
9742
|
+
}
|
|
9743
|
+
}
|
|
9744
|
+
return snapshot;
|
|
9745
|
+
}
|
|
9746
|
+
static AreTopologySnapshotsEqual(left, right) {
|
|
9747
|
+
return left.length === right.length && left.every((value, index) => Object.is(value, right[index]));
|
|
9748
|
+
}
|
|
9749
|
+
getSceneSnapshot(scene) {
|
|
9750
|
+
return this._sceneSnapshots.get(scene) ?? { scene, materials: [], textures: [] };
|
|
9751
|
+
}
|
|
9752
|
+
getMaterialRecord(material) {
|
|
9753
|
+
return this._materialRecords.get(material);
|
|
9754
|
+
}
|
|
9755
|
+
getTextureRecord(texture) {
|
|
9756
|
+
return this._textureRecords.get(texture);
|
|
9757
|
+
}
|
|
9758
|
+
dispose() {
|
|
9759
|
+
this._sceneSnapshots.clear();
|
|
9760
|
+
this._materialRecords.clear();
|
|
9761
|
+
this._textureRecords.clear();
|
|
9762
|
+
this._textureOrdinals = new WeakMap();
|
|
9763
|
+
}
|
|
9764
|
+
_getTextureOrdinal(texture) {
|
|
9765
|
+
let ordinal = this._textureOrdinals.get(texture);
|
|
9766
|
+
if (ordinal === undefined) {
|
|
9767
|
+
ordinal = this._nextTextureOrdinal++;
|
|
9768
|
+
this._textureOrdinals.set(texture, ordinal);
|
|
9769
|
+
}
|
|
9770
|
+
return ordinal;
|
|
9771
|
+
}
|
|
9772
|
+
_getScenes() {
|
|
9773
|
+
const scenes = [];
|
|
9774
|
+
const seen = new Set();
|
|
9775
|
+
for (const surface of this._engine.surfaces) {
|
|
9776
|
+
for (const context of getRenderingContexts(surface)) {
|
|
9777
|
+
if (getRenderingContextKind(context) === "scene" && !seen.has(context)) {
|
|
9778
|
+
const scene = context;
|
|
9779
|
+
seen.add(scene);
|
|
9780
|
+
scenes.push(scene);
|
|
9781
|
+
}
|
|
9782
|
+
}
|
|
9783
|
+
}
|
|
9784
|
+
return scenes;
|
|
9785
|
+
}
|
|
9786
|
+
}
|
|
9787
|
+
|
|
9788
|
+
/**
|
|
9789
|
+
* The unique identity for the Inspector-owned Lite scene resource index.
|
|
9790
|
+
* @internal
|
|
9791
|
+
*/
|
|
9792
|
+
const SceneResourceIndexServiceIdentity = Symbol("SceneResourceIndex");
|
|
9793
|
+
/**
|
|
9794
|
+
* Creates one disposable Lite scene resource index per Inspector service container.
|
|
9795
|
+
* @internal
|
|
9796
|
+
*/
|
|
9797
|
+
const SceneResourceIndexServiceDefinition = {
|
|
9798
|
+
friendlyName: "Babylon Lite Scene Resource Index",
|
|
9799
|
+
produces: [SceneResourceIndexServiceIdentity],
|
|
9800
|
+
consumes: [EngineContextIdentity, WatcherServiceIdentity],
|
|
9801
|
+
factory: (engineContext, watcherService) => {
|
|
9802
|
+
const index = new SceneResourceIndex(engineContext.engine);
|
|
9803
|
+
const onChanged = new Observable();
|
|
9804
|
+
const onDisposed = new Observable();
|
|
9805
|
+
let refreshPending = false;
|
|
9806
|
+
let isDisposed = false;
|
|
9807
|
+
const topologyWatcher = watcherService.watchValue(() => index.getTopologySnapshot(), () => {
|
|
9808
|
+
if (refreshPending || isDisposed) {
|
|
9809
|
+
return;
|
|
9810
|
+
}
|
|
9811
|
+
refreshPending = true;
|
|
9812
|
+
queueMicrotask(() => {
|
|
9813
|
+
refreshPending = false;
|
|
9814
|
+
if (!isDisposed) {
|
|
9815
|
+
index.refresh();
|
|
9816
|
+
onChanged.notifyObservers();
|
|
9817
|
+
}
|
|
9818
|
+
});
|
|
9819
|
+
}, SceneResourceIndex.AreTopologySnapshotsEqual);
|
|
9820
|
+
return {
|
|
9821
|
+
getSceneSnapshot: (scene) => index.getSceneSnapshot(scene),
|
|
9822
|
+
getMaterialRecord: (material) => index.getMaterialRecord(material),
|
|
9823
|
+
getTextureRecord: (texture) => index.getTextureRecord(texture),
|
|
9824
|
+
onChanged,
|
|
9825
|
+
onDisposed,
|
|
9826
|
+
get isDisposed() {
|
|
9827
|
+
return isDisposed;
|
|
9828
|
+
},
|
|
9829
|
+
refresh: () => {
|
|
9830
|
+
if (!isDisposed) {
|
|
9831
|
+
index.refresh();
|
|
9832
|
+
onChanged.notifyObservers();
|
|
9833
|
+
}
|
|
9834
|
+
},
|
|
9835
|
+
dispose: () => {
|
|
9836
|
+
if (isDisposed) {
|
|
9837
|
+
return;
|
|
9838
|
+
}
|
|
9839
|
+
isDisposed = true;
|
|
9840
|
+
topologyWatcher.dispose();
|
|
9841
|
+
onDisposed.notifyObservers();
|
|
9842
|
+
onDisposed.clear();
|
|
9843
|
+
index.dispose();
|
|
9844
|
+
onChanged.clear();
|
|
9845
|
+
},
|
|
9846
|
+
};
|
|
9847
|
+
},
|
|
9848
|
+
};
|
|
9849
|
+
|
|
9850
|
+
const StandardMaterialAdapter = MakeLazyComponent(async () => (await import('./standardMaterialProperties-BbYdFX86.js')).StandardMaterialAdapter, {
|
|
9851
|
+
spinnerLabel: "Loading Standard material properties",
|
|
9852
|
+
});
|
|
9853
|
+
const PbrMaterialAdapter = MakeLazyComponent(async () => (await import('./pbrMaterialProperties-jfJddBxY.js')).PbrMaterialAdapter, {
|
|
9854
|
+
spinnerLabel: "Loading PBR material properties",
|
|
9855
|
+
});
|
|
9856
|
+
const ShaderMaterialAdapter = MakeLazyComponent(async () => (await import('./shaderMaterialProperties-CTH_KfBK.js')).ShaderMaterialAdapter, {
|
|
9857
|
+
spinnerLabel: "Loading Shader material properties",
|
|
9858
|
+
});
|
|
9859
|
+
const NodeMaterialAdapter = MakeLazyComponent(async () => (await import('./nodeMaterialProperties-ELFMlzS1.js')).NodeMaterialAdapter, {
|
|
9860
|
+
spinnerLabel: "Loading Node material properties",
|
|
9861
|
+
});
|
|
9862
|
+
const FamilyConfigurations = {
|
|
9863
|
+
standard: {
|
|
9864
|
+
component: StandardMaterialAdapter,
|
|
9865
|
+
sections: ["general", "transparency", "lighting-colors", "textures", "texture-settings", "transform", "stencil"],
|
|
9866
|
+
},
|
|
9867
|
+
pbr: {
|
|
9868
|
+
component: PbrMaterialAdapter,
|
|
9869
|
+
sections: [
|
|
9870
|
+
"general",
|
|
9871
|
+
"transparency",
|
|
9872
|
+
"lighting-colors",
|
|
9873
|
+
"textures",
|
|
9874
|
+
"occlusion",
|
|
9875
|
+
"lightmap",
|
|
9876
|
+
"metallic-reflectance",
|
|
9877
|
+
"clear-coat",
|
|
9878
|
+
"sheen",
|
|
9879
|
+
"iridescence",
|
|
9880
|
+
"anisotropy",
|
|
9881
|
+
"subsurface-translucency",
|
|
9882
|
+
"subsurface-thickness",
|
|
9883
|
+
"subsurface-tint",
|
|
9884
|
+
"transmission",
|
|
9885
|
+
"special-modes",
|
|
9886
|
+
"transform",
|
|
9887
|
+
"stencil",
|
|
9888
|
+
],
|
|
9889
|
+
},
|
|
9890
|
+
shader: {
|
|
9891
|
+
component: ShaderMaterialAdapter,
|
|
9892
|
+
sections: ["general", "inputs", "textures", "configuration"],
|
|
9893
|
+
},
|
|
9894
|
+
node: {
|
|
9895
|
+
component: NodeMaterialAdapter,
|
|
9896
|
+
sections: ["general", "inputs"],
|
|
9897
|
+
},
|
|
9898
|
+
};
|
|
9899
|
+
function GetSectionLabel(section) {
|
|
9900
|
+
return section
|
|
9901
|
+
.split("-")
|
|
9902
|
+
.map((part) => part[0].toUpperCase() + part.slice(1))
|
|
9903
|
+
.join(" ")
|
|
9904
|
+
.replace("Lighting Colors", "Lighting & Colors")
|
|
9905
|
+
.replace("Subsurface ", "Subsurface / ");
|
|
9906
|
+
}
|
|
9907
|
+
function TryDescribeMaterial(entity, resourceIndexService) {
|
|
9908
|
+
if (typeof entity !== "object" || entity === null) {
|
|
9909
|
+
return undefined;
|
|
9910
|
+
}
|
|
9911
|
+
try {
|
|
9912
|
+
const material = entity;
|
|
9913
|
+
const source = getMaterialSource(material);
|
|
9914
|
+
const record = typeof source === "object" && source !== null ? resourceIndexService.getMaterialRecord(source) : undefined;
|
|
9915
|
+
if (!record || !GetMaterialOwningScenes(record, material).length) {
|
|
9916
|
+
return undefined;
|
|
9917
|
+
}
|
|
9918
|
+
const family = getMaterialFamily(source);
|
|
9919
|
+
const name = material.name;
|
|
9920
|
+
const displayName = typeof name === "string" && name.length > 0 ? name : family ? `${family[0].toUpperCase()}${family.slice(1)} Material` : "Material";
|
|
9921
|
+
return { source, family, displayName, isView: isMaterialView(material) };
|
|
9922
|
+
}
|
|
9923
|
+
catch {
|
|
9924
|
+
return undefined;
|
|
9925
|
+
}
|
|
9926
|
+
}
|
|
9927
|
+
function IsSupportedFamily(family) {
|
|
9928
|
+
return family === "standard" || family === "pbr" || family === "shader" || family === "node";
|
|
9929
|
+
}
|
|
9930
|
+
const UnknownMaterialProperties = (props) => {
|
|
9931
|
+
const { material, resourceIndexService } = props;
|
|
9932
|
+
const getMaterialIdentity = useCallback(() => {
|
|
9933
|
+
const identity = TryDescribeMaterial(material, resourceIndexService);
|
|
9934
|
+
const record = identity && resourceIndexService.getMaterialRecord(identity.source);
|
|
9935
|
+
return record && identity ? identity : undefined;
|
|
9936
|
+
}, [material, resourceIndexService]);
|
|
9937
|
+
const identity = useObservableState(getMaterialIdentity, resourceIndexService.onChanged);
|
|
9938
|
+
if (!identity) {
|
|
9939
|
+
return jsx(TextPropertyLine, { label: "Error", value: "This material is unavailable." });
|
|
9940
|
+
}
|
|
9941
|
+
return (jsxs(Fragment, { children: [jsx(TextPropertyLine, { label: "Name", value: identity.displayName }), jsx(TextPropertyLine, { label: "Family", value: identity.family ?? "Unknown" }), jsx(TextPropertyLine, { label: "Selection", value: identity.isView ? "MaterialView" : "Material" }), identity.isView ? jsx(TextPropertyLine, { label: "Source", value: resourceIndexService.getMaterialRecord(identity.source)?.displayName ?? "Unavailable" }) : undefined] }));
|
|
9942
|
+
};
|
|
9943
|
+
const MaterialPropertiesServiceDefinition = {
|
|
9944
|
+
friendlyName: "Babylon Lite Material Properties",
|
|
9945
|
+
consumes: [PropertiesServiceIdentity, SceneResourceIndexServiceIdentity, SelectionServiceIdentity],
|
|
9946
|
+
factory: (propertiesService, resourceIndexService, selectionService) => {
|
|
9947
|
+
const registrations = Object.entries(FamilyConfigurations).map(([family, configuration]) => propertiesService.addSectionContent({
|
|
9948
|
+
key: `Babylon Lite ${family} Material Properties`,
|
|
9949
|
+
predicate: (entity) => TryDescribeMaterial(entity, resourceIndexService)?.family === family,
|
|
9950
|
+
content: configuration.sections.map((section) => {
|
|
9951
|
+
const component = configuration.component;
|
|
9952
|
+
const sectionContent = (props) => {
|
|
9953
|
+
const { context } = props;
|
|
9954
|
+
return createElement(component, { material: context, section, resourceIndexService, selectionService });
|
|
9955
|
+
};
|
|
9956
|
+
return {
|
|
9957
|
+
section: GetSectionLabel(section),
|
|
9958
|
+
component: sectionContent,
|
|
9959
|
+
};
|
|
9960
|
+
}),
|
|
9961
|
+
}));
|
|
9962
|
+
registrations.push(propertiesService.addSectionContent({
|
|
9963
|
+
key: "Babylon Lite Unknown Material Properties",
|
|
9964
|
+
predicate: (entity) => {
|
|
9965
|
+
const identity = TryDescribeMaterial(entity, resourceIndexService);
|
|
9966
|
+
return identity !== undefined && !IsSupportedFamily(identity.family);
|
|
9967
|
+
},
|
|
9968
|
+
content: [
|
|
9969
|
+
{
|
|
9970
|
+
section: "General",
|
|
9971
|
+
component: ({ context }) => jsx(UnknownMaterialProperties, { material: context, resourceIndexService: resourceIndexService }),
|
|
9972
|
+
},
|
|
9973
|
+
],
|
|
9974
|
+
}));
|
|
9975
|
+
return {
|
|
9976
|
+
dispose: () => registrations.forEach((registration) => registration.dispose()),
|
|
9977
|
+
};
|
|
9978
|
+
},
|
|
9979
|
+
};
|
|
9980
|
+
|
|
8882
9981
|
const MeshGeneralProperties = (props) => {
|
|
8883
9982
|
const { mesh } = props;
|
|
8884
9983
|
return jsx(BoundProperty, { component: SwitchPropertyLine, label: "Receive Shadows", target: mesh, propertyKey: "receiveShadows" });
|
|
@@ -8969,161 +10068,6 @@ const RenderingContextPropertiesServiceDefinition = {
|
|
|
8969
10068
|
},
|
|
8970
10069
|
};
|
|
8971
10070
|
|
|
8972
|
-
const PrettyJSONIndent = 2;
|
|
8973
|
-
function IsParsable(metadata) {
|
|
8974
|
-
try {
|
|
8975
|
-
const parsed = JSON.parse(metadata);
|
|
8976
|
-
return !!parsed && !IsString(parsed);
|
|
8977
|
-
}
|
|
8978
|
-
catch {
|
|
8979
|
-
return false;
|
|
8980
|
-
}
|
|
8981
|
-
}
|
|
8982
|
-
/**
|
|
8983
|
-
* Checks if the input is a string.
|
|
8984
|
-
* @param input - any input to check
|
|
8985
|
-
* @returns boolean - true if the input is a string, false otherwise
|
|
8986
|
-
*/
|
|
8987
|
-
function IsString(input) {
|
|
8988
|
-
return typeof input === "string" || input instanceof String;
|
|
8989
|
-
}
|
|
8990
|
-
/**
|
|
8991
|
-
* Checks recursively for functions on an object and returns `false` if any are found.
|
|
8992
|
-
* @param o any object, string or number
|
|
8993
|
-
* @returns boolean
|
|
8994
|
-
*/
|
|
8995
|
-
function ObjectCanSafelyStringify(o) {
|
|
8996
|
-
if (typeof o === "function") {
|
|
8997
|
-
return false;
|
|
8998
|
-
}
|
|
8999
|
-
if (o === null || o === true || o === false || typeof o === "number" || IsString(o)) {
|
|
9000
|
-
return true;
|
|
9001
|
-
}
|
|
9002
|
-
if (typeof o === "object") {
|
|
9003
|
-
if (Object.values(o).length === 0) {
|
|
9004
|
-
return true;
|
|
9005
|
-
}
|
|
9006
|
-
return Object.values(o).every((value) => ObjectCanSafelyStringify(value));
|
|
9007
|
-
}
|
|
9008
|
-
if (Array.isArray(o)) {
|
|
9009
|
-
return o.every((value) => ObjectCanSafelyStringify(value));
|
|
9010
|
-
}
|
|
9011
|
-
return false;
|
|
9012
|
-
}
|
|
9013
|
-
function GetMetadataEntityType(metadata) {
|
|
9014
|
-
if (metadata == null) {
|
|
9015
|
-
return "null";
|
|
9016
|
-
}
|
|
9017
|
-
else if (IsString(metadata)) {
|
|
9018
|
-
return "string";
|
|
9019
|
-
}
|
|
9020
|
-
else if (!ObjectCanSafelyStringify(metadata)) {
|
|
9021
|
-
return "object";
|
|
9022
|
-
}
|
|
9023
|
-
else {
|
|
9024
|
-
return "JSON";
|
|
9025
|
-
}
|
|
9026
|
-
}
|
|
9027
|
-
function HasGltfExtras(metadata) {
|
|
9028
|
-
return IsParsable(metadata) && !!JSON.parse(metadata).gltf;
|
|
9029
|
-
}
|
|
9030
|
-
function StringifyMetadata(metadata, format) {
|
|
9031
|
-
if (IsString(metadata)) {
|
|
9032
|
-
return metadata;
|
|
9033
|
-
}
|
|
9034
|
-
if (metadata) {
|
|
9035
|
-
// Try JSON.stringify even for objects with functions — it safely omits
|
|
9036
|
-
// function-valued and undefined properties. Only fall back to String()
|
|
9037
|
-
// for cases that actually throw (e.g. circular references).
|
|
9038
|
-
try {
|
|
9039
|
-
return JSON.stringify(metadata, undefined, format ? PrettyJSONIndent : undefined);
|
|
9040
|
-
}
|
|
9041
|
-
catch {
|
|
9042
|
-
return String(metadata);
|
|
9043
|
-
}
|
|
9044
|
-
}
|
|
9045
|
-
return null;
|
|
9046
|
-
}
|
|
9047
|
-
function Restringify(value, format) {
|
|
9048
|
-
return IsParsable(value) ? JSON.stringify(JSON.parse(value), undefined, format ? PrettyJSONIndent : undefined) : value;
|
|
9049
|
-
}
|
|
9050
|
-
function PopulateGLTFExtras(metadata) {
|
|
9051
|
-
if (!metadata) {
|
|
9052
|
-
metadata = "{}";
|
|
9053
|
-
}
|
|
9054
|
-
if (!IsParsable(metadata)) {
|
|
9055
|
-
return metadata;
|
|
9056
|
-
}
|
|
9057
|
-
try {
|
|
9058
|
-
const parsedJson = JSON.parse(metadata);
|
|
9059
|
-
if (parsedJson) {
|
|
9060
|
-
if (Reflect.has(parsedJson, "gltf")) {
|
|
9061
|
-
if (!Reflect.has(parsedJson.gltf, "extras")) {
|
|
9062
|
-
parsedJson.gltf.extras = {};
|
|
9063
|
-
}
|
|
9064
|
-
}
|
|
9065
|
-
else {
|
|
9066
|
-
parsedJson.gltf = { extras: {} };
|
|
9067
|
-
}
|
|
9068
|
-
}
|
|
9069
|
-
return JSON.stringify(parsedJson);
|
|
9070
|
-
}
|
|
9071
|
-
catch {
|
|
9072
|
-
return metadata;
|
|
9073
|
-
}
|
|
9074
|
-
}
|
|
9075
|
-
function SaveMetadata(entity, metadata) {
|
|
9076
|
-
if (IsParsable(metadata)) {
|
|
9077
|
-
entity.metadata = JSON.parse(metadata);
|
|
9078
|
-
}
|
|
9079
|
-
else {
|
|
9080
|
-
entity.metadata = metadata;
|
|
9081
|
-
}
|
|
9082
|
-
}
|
|
9083
|
-
const useStyles = makeStyles({
|
|
9084
|
-
mainDiv: {
|
|
9085
|
-
display: "flex",
|
|
9086
|
-
flexDirection: "column",
|
|
9087
|
-
gap: tokens.spacingVerticalXS,
|
|
9088
|
-
},
|
|
9089
|
-
buttonDiv: {
|
|
9090
|
-
display: "grid",
|
|
9091
|
-
gridAutoFlow: "column",
|
|
9092
|
-
gridTemplateColumns: "1fr auto auto auto",
|
|
9093
|
-
gap: tokens.spacingHorizontalXS,
|
|
9094
|
-
},
|
|
9095
|
-
});
|
|
9096
|
-
/**
|
|
9097
|
-
* Component to display metadata properties of an entity.
|
|
9098
|
-
* @param props - The properties for the component.
|
|
9099
|
-
* @returns A React component that displays metadata properties.
|
|
9100
|
-
*/
|
|
9101
|
-
const MetadataProperties = (props) => {
|
|
9102
|
-
const { entity } = props;
|
|
9103
|
-
const classes = useStyles();
|
|
9104
|
-
const { size } = useContext(ToolContext);
|
|
9105
|
-
const metadata = useProperty(entity, "metadata");
|
|
9106
|
-
const stringifiedMetadata = useMemo(() => StringifyMetadata(metadata, false) ?? "", [metadata]);
|
|
9107
|
-
const metadataType = useMemo(() => GetMetadataEntityType(metadata), [metadata]);
|
|
9108
|
-
const canPreventObjectCorruption = metadataType === "object";
|
|
9109
|
-
const [preventObjectCorruption, setPreventObjectCorruption] = useState(false);
|
|
9110
|
-
const isReadonly = canPreventObjectCorruption && preventObjectCorruption;
|
|
9111
|
-
const [editedMetadata, setEditedMetadata] = useState(stringifiedMetadata);
|
|
9112
|
-
useEffect(() => {
|
|
9113
|
-
setEditedMetadata(stringifiedMetadata);
|
|
9114
|
-
}, [stringifiedMetadata]);
|
|
9115
|
-
const isEditedMetadataJSON = useMemo(() => IsParsable(editedMetadata), [editedMetadata]);
|
|
9116
|
-
const unformattedEditedMetadata = useMemo(() => Restringify(editedMetadata, false), [editedMetadata]);
|
|
9117
|
-
return (jsxs(Fragment, { children: [jsx(TextPropertyLine, { label: "Property Type", value: metadataType }), jsx(Collapse, { visible: canPreventObjectCorruption, children: jsx(SwitchPropertyLine, { label: "Prevent Object Corruption", value: isReadonly, onChange: setPreventObjectCorruption }) }), jsx(LineContainer, { uniqueId: "MetadataTextarea", children: jsx(Textarea, { disabled: isReadonly, value: editedMetadata, onChange: setEditedMetadata }) }), jsx(ButtonLine, { label: "Populate glTF extras", disabled: !!editedMetadata && (!IsParsable(editedMetadata) || HasGltfExtras(editedMetadata)), onClick: () => {
|
|
9118
|
-
const isFormatted = Restringify(editedMetadata, true) === editedMetadata;
|
|
9119
|
-
let withGLTFExtras = PopulateGLTFExtras(editedMetadata);
|
|
9120
|
-
if (isFormatted) {
|
|
9121
|
-
withGLTFExtras = Restringify(withGLTFExtras, true);
|
|
9122
|
-
}
|
|
9123
|
-
setEditedMetadata(withGLTFExtras);
|
|
9124
|
-
} }), jsx(LineContainer, { uniqueId: "MetadataButtonDiv", children: jsxs("div", { className: classes.buttonDiv, children: [jsx(Button$1, { size: size, icon: jsx(SaveRegular, {}), disabled: stringifiedMetadata === unformattedEditedMetadata, onClick: () => SaveMetadata(entity, editedMetadata), children: jsx(Body1, { children: "Save" }) }), jsx(Tooltip$1, { content: "Undo Changes", relationship: "label", children: jsx(Button$1, { size: size, icon: jsx(ArrowUndoRegular, {}), disabled: stringifiedMetadata === unformattedEditedMetadata, onClick: () => setEditedMetadata(stringifiedMetadata) }) }), jsx(Tooltip$1, { content: "Format (Pretty Print)", relationship: "label", children: jsx(Button$1, { size: size, icon: jsx(BracesRegular, {}), disabled: !isEditedMetadataJSON, onClick: () => setEditedMetadata(Restringify(editedMetadata, true)) }) }), jsx(Tooltip$1, { content: "Clear Formatting (Undo Pretty Print)", relationship: "label", children: jsx(Button$1, { size: size, icon: jsx(BracesDismiss16Regular, {}), disabled: !isEditedMetadataJSON, onClick: () => setEditedMetadata(Restringify(editedMetadata, false)) }) })] }) })] }));
|
|
9125
|
-
};
|
|
9126
|
-
|
|
9127
10071
|
function GetPosition$1(node) {
|
|
9128
10072
|
return [node.position.x, node.position.y, node.position.z];
|
|
9129
10073
|
}
|
|
@@ -9421,30 +10365,48 @@ const TextLayerPropertiesServiceDefinition = {
|
|
|
9421
10365
|
}),
|
|
9422
10366
|
};
|
|
9423
10367
|
|
|
9424
|
-
|
|
10368
|
+
const TextureMetadataProperties = MakeLazyComponent(async () => (await import('./textureMetadataProperties-BdNmp0Pk.js')).TextureMetadataProperties, {
|
|
10369
|
+
spinnerLabel: "Loading texture metadata",
|
|
10370
|
+
});
|
|
10371
|
+
function TryGetTextureMetadata(entity) {
|
|
9425
10372
|
if (typeof entity !== "object" || entity === null) {
|
|
9426
10373
|
return false;
|
|
9427
10374
|
}
|
|
9428
|
-
|
|
9429
|
-
|
|
10375
|
+
try {
|
|
10376
|
+
return getTextureMetadata(entity) !== undefined;
|
|
10377
|
+
}
|
|
10378
|
+
catch {
|
|
10379
|
+
return false;
|
|
10380
|
+
}
|
|
9430
10381
|
}
|
|
9431
|
-
const TextureProperties = (props) => {
|
|
9432
|
-
const { texture } = props;
|
|
9433
|
-
return (jsxs(Fragment, { children: [jsx(StringifiedPropertyLine, { label: "Width", value: texture.width, units: "px" }), jsx(StringifiedPropertyLine, { label: "Height", value: texture.height, units: "px" }), jsx(BooleanBadgePropertyLine, { label: "Invert Y", value: texture.invertY ?? false })] }));
|
|
9434
|
-
};
|
|
9435
10382
|
const TexturePropertiesServiceDefinition = {
|
|
9436
10383
|
friendlyName: "Babylon Lite Texture Properties",
|
|
9437
|
-
consumes: [PropertiesServiceIdentity],
|
|
9438
|
-
factory: (propertiesService) =>
|
|
9439
|
-
|
|
9440
|
-
|
|
9441
|
-
|
|
9442
|
-
{
|
|
9443
|
-
|
|
9444
|
-
|
|
10384
|
+
consumes: [PropertiesServiceIdentity, SceneResourceIndexServiceIdentity, SelectionServiceIdentity],
|
|
10385
|
+
factory: (propertiesService, resourceIndexService, selectionService) => {
|
|
10386
|
+
const recognizedTextures = new WeakSet();
|
|
10387
|
+
return propertiesService.addSectionContent({
|
|
10388
|
+
key: "Babylon Lite Texture Properties",
|
|
10389
|
+
predicate: (entity) => {
|
|
10390
|
+
if (typeof entity !== "object" || entity === null) {
|
|
10391
|
+
return false;
|
|
10392
|
+
}
|
|
10393
|
+
if (TryGetTextureMetadata(entity) || resourceIndexService.getTextureRecord(entity)) {
|
|
10394
|
+
recognizedTextures.add(entity);
|
|
10395
|
+
return true;
|
|
10396
|
+
}
|
|
10397
|
+
return recognizedTextures.has(entity);
|
|
9445
10398
|
},
|
|
9446
|
-
|
|
9447
|
-
|
|
10399
|
+
content: [
|
|
10400
|
+
{
|
|
10401
|
+
section: "General",
|
|
10402
|
+
component: ((props) => {
|
|
10403
|
+
const { context } = props;
|
|
10404
|
+
return createElement(TextureMetadataProperties, { texture: context, resourceIndexService, selectionService });
|
|
10405
|
+
}),
|
|
10406
|
+
},
|
|
10407
|
+
],
|
|
10408
|
+
});
|
|
10409
|
+
},
|
|
9448
10410
|
};
|
|
9449
10411
|
|
|
9450
10412
|
function ClearRemovedSelection(selectionService, engineContext, selectionWasRemoved) {
|
|
@@ -9499,6 +10461,103 @@ const CameraExplorerServiceDefinition = {
|
|
|
9499
10461
|
},
|
|
9500
10462
|
};
|
|
9501
10463
|
|
|
10464
|
+
const AnimationGroupIcon = () => jsx(StackRegular, { color: tokens.colorPaletteBlueForeground2 });
|
|
10465
|
+
const TargetedAnimationIcon = () => jsx(FilmstripRegular, { color: tokens.colorPaletteBlueForeground2 });
|
|
10466
|
+
const AnimationGroupExplorerServiceDefinition = {
|
|
10467
|
+
friendlyName: "Babylon Lite Animation Group Explorer",
|
|
10468
|
+
consumes: [EngineExplorerServiceIdentity, ExplorerServiceIdentity, WatcherServiceIdentity, EngineContextIdentity, SelectionServiceIdentity],
|
|
10469
|
+
factory: (engineExplorerService, explorerService, watcherService, engineContext, selectionService) => {
|
|
10470
|
+
const engine = engineContext.engine;
|
|
10471
|
+
const providerRegistration = engineExplorerService.addRenderingContextNodeProvider({
|
|
10472
|
+
order: 300,
|
|
10473
|
+
predicate: IsSceneContext,
|
|
10474
|
+
getNodes: (scene) => [
|
|
10475
|
+
{
|
|
10476
|
+
id: "animation-groups",
|
|
10477
|
+
kind: "group",
|
|
10478
|
+
getDisplayInfo: () => ({ name: "Animation Groups" }),
|
|
10479
|
+
getChildren: () => scene.animationGroups.map((group) => ({
|
|
10480
|
+
id: GetEntityId(group).toString(),
|
|
10481
|
+
kind: "item",
|
|
10482
|
+
entity: group,
|
|
10483
|
+
icon: AnimationGroupIcon,
|
|
10484
|
+
getDisplayInfo: () => CreateWatchedNameDisplayInfo(watcherService, group, () => group.name || "Unnamed Animation Group"),
|
|
10485
|
+
getChildren: () => group.targetedAnimations.map((animation) => ({
|
|
10486
|
+
id: GetEntityId(animation).toString(),
|
|
10487
|
+
kind: "item",
|
|
10488
|
+
entity: animation,
|
|
10489
|
+
icon: TargetedAnimationIcon,
|
|
10490
|
+
getDisplayInfo: () => {
|
|
10491
|
+
const onChange = new Observable();
|
|
10492
|
+
const watcher = watcherService.watchValue(() => GetTargetedAnimationDisplayName(animation), () => onChange.notifyObservers());
|
|
10493
|
+
return {
|
|
10494
|
+
get name() {
|
|
10495
|
+
return GetTargetedAnimationDisplayName(animation);
|
|
10496
|
+
},
|
|
10497
|
+
onChange,
|
|
10498
|
+
dispose: () => {
|
|
10499
|
+
watcher.dispose();
|
|
10500
|
+
onChange.clear();
|
|
10501
|
+
},
|
|
10502
|
+
};
|
|
10503
|
+
},
|
|
10504
|
+
})),
|
|
10505
|
+
})),
|
|
10506
|
+
},
|
|
10507
|
+
],
|
|
10508
|
+
getSnapshot: (scene) => scene.animationGroups.flatMap((group) => [group, ...group.targetedAnimations]),
|
|
10509
|
+
});
|
|
10510
|
+
const playPauseRegistration = explorerService.addItemCommand({
|
|
10511
|
+
predicate: (entity) => IsAnimationGroup(engine, entity),
|
|
10512
|
+
order: 1100,
|
|
10513
|
+
getCommand: (group) => {
|
|
10514
|
+
const onChange = new Observable();
|
|
10515
|
+
const watcher = watcherService.watchProperty(group, "isPlaying", () => onChange.notifyObservers());
|
|
10516
|
+
return {
|
|
10517
|
+
type: "toggle",
|
|
10518
|
+
get displayName() {
|
|
10519
|
+
return `${group.isPlaying ? "Pause" : "Play"} Animation`;
|
|
10520
|
+
},
|
|
10521
|
+
icon: () => (group.isPlaying ? jsx(PauseFilled, {}) : jsx(PlayFilled, {})),
|
|
10522
|
+
hotKey: { keyCode: "Space", control: true },
|
|
10523
|
+
get isEnabled() {
|
|
10524
|
+
return group.isPlaying;
|
|
10525
|
+
},
|
|
10526
|
+
set isEnabled(enabled) {
|
|
10527
|
+
if (enabled) {
|
|
10528
|
+
playAnimation(group);
|
|
10529
|
+
}
|
|
10530
|
+
else {
|
|
10531
|
+
pauseAnimation(group);
|
|
10532
|
+
}
|
|
10533
|
+
watcherService.refresh();
|
|
10534
|
+
},
|
|
10535
|
+
onChange,
|
|
10536
|
+
dispose: () => {
|
|
10537
|
+
watcher.dispose();
|
|
10538
|
+
onChange.clear();
|
|
10539
|
+
},
|
|
10540
|
+
};
|
|
10541
|
+
},
|
|
10542
|
+
});
|
|
10543
|
+
const getAnimationEntities = () => GetSceneAnimationGroups(engine).flatMap((group) => [group, ...group.targetedAnimations]);
|
|
10544
|
+
let previousEntities = getAnimationEntities();
|
|
10545
|
+
const selectionWatcher = watcherService.watchValue(getAnimationEntities, (entities) => {
|
|
10546
|
+
if (selectionService.selectedEntity && previousEntities.includes(selectionService.selectedEntity) && !entities.includes(selectionService.selectedEntity)) {
|
|
10547
|
+
selectionService.selectedEntity = null;
|
|
10548
|
+
}
|
|
10549
|
+
previousEntities = entities;
|
|
10550
|
+
}, (left, right) => left.length === right.length && left.every((entity, index) => entity === right[index]));
|
|
10551
|
+
return {
|
|
10552
|
+
dispose: () => {
|
|
10553
|
+
selectionWatcher.dispose();
|
|
10554
|
+
playPauseRegistration.dispose();
|
|
10555
|
+
providerRegistration.dispose();
|
|
10556
|
+
},
|
|
10557
|
+
};
|
|
10558
|
+
},
|
|
10559
|
+
};
|
|
10560
|
+
|
|
9502
10561
|
const LightIcon = () => jsx(LightbulbRegular, { color: tokens.colorPaletteYellowForeground2 });
|
|
9503
10562
|
const LightExplorerServiceDefinition = {
|
|
9504
10563
|
friendlyName: "Babylon Lite Light Explorer",
|
|
@@ -9550,37 +10609,23 @@ createFluentIcon("BreakTangent", "20", '<g transform="scale(0.5)"><path d="M27.1
|
|
|
9550
10609
|
createFluentIcon("UnifyTangent", "20", '<g transform="scale(0.5)"><path d="M27.94,18.28a1.49,1.49,0,0,0-1.41,1h-5l-1.62-1.63-1.62,1.63h-5a1.5,1.5,0,1,0,0,1h5l1.62,1.62,1.62-1.62h5a1.5,1.5,0,1,0,1.41-2Z"/></g>');
|
|
9551
10610
|
createFluentIcon("StepTangent", "20", '<g transform="scale(0.5)"><path d="M29,16.71a1.5,1.5,0,1,0-2,1.41v5.67H11v1H28V18.12A1.51,1.51,0,0,0,29,16.71Z"/></g>');
|
|
9552
10611
|
|
|
9553
|
-
/**
|
|
9554
|
-
* Gets the unique materials referenced by a scene's meshes.
|
|
9555
|
-
* @param scene The scene to inspect.
|
|
9556
|
-
* @returns The referenced materials in mesh order.
|
|
9557
|
-
*/
|
|
9558
|
-
function GetSceneMaterials(scene) {
|
|
9559
|
-
return [...new Set(scene.meshes.map((mesh) => mesh.material))];
|
|
9560
|
-
}
|
|
9561
|
-
/**
|
|
9562
|
-
* Gets the unique textures referenced by a scene's materials.
|
|
9563
|
-
* @param scene The scene to inspect.
|
|
9564
|
-
* @returns The referenced textures in material order.
|
|
9565
|
-
*/
|
|
9566
|
-
function GetSceneTextures(scene) {
|
|
9567
|
-
return [...new Set(GetSceneMaterials(scene).flatMap((material) => getMaterialTextures(material)))];
|
|
9568
|
-
}
|
|
9569
|
-
|
|
9570
10612
|
function GetMaterialDisplayName(material) {
|
|
9571
10613
|
const family = getMaterialFamily(material);
|
|
9572
10614
|
return material.name ?? (family ? `${family.charAt(0).toUpperCase()}${family.slice(1)} Material` : "Material");
|
|
9573
10615
|
}
|
|
9574
10616
|
const MaterialExplorerServiceDefinition = {
|
|
9575
10617
|
friendlyName: "Babylon Lite Material Explorer",
|
|
9576
|
-
consumes: [EngineExplorerServiceIdentity, WatcherServiceIdentity],
|
|
9577
|
-
factory: (engineExplorerService, watcherService) => engineExplorerService.addRenderingContextNodeProvider({
|
|
10618
|
+
consumes: [EngineExplorerServiceIdentity, WatcherServiceIdentity, SceneResourceIndexServiceIdentity],
|
|
10619
|
+
factory: (engineExplorerService, watcherService, resourceIndexService) => engineExplorerService.addRenderingContextNodeProvider({
|
|
9578
10620
|
order: 100,
|
|
9579
10621
|
predicate: IsSceneContext,
|
|
9580
|
-
getNodes: (scene) =>
|
|
9581
|
-
|
|
9582
|
-
|
|
9583
|
-
|
|
10622
|
+
getNodes: (scene) => {
|
|
10623
|
+
return [
|
|
10624
|
+
CreateSceneExplorerSectionNode("materials", "Materials", resourceIndexService.getSceneSnapshot(scene).materials.map((record) => record.source), (material) => CreateWatchedNameDisplayInfo(watcherService, material, () => GetMaterialDisplayName(material)), () => jsx(MaterialIcon, { color: tokens.colorPaletteMarigoldForeground2 })),
|
|
10625
|
+
];
|
|
10626
|
+
},
|
|
10627
|
+
getSnapshot: (scene) => resourceIndexService.getSceneSnapshot(scene).materials.map((record) => record.source),
|
|
10628
|
+
onChanged: resourceIndexService.onChanged,
|
|
9584
10629
|
}),
|
|
9585
10630
|
};
|
|
9586
10631
|
|
|
@@ -9829,19 +10874,29 @@ const TextLayerExplorerServiceDefinition = CreateRenderingLayerExplorerServiceDe
|
|
|
9829
10874
|
icon: TextLayerIcon,
|
|
9830
10875
|
});
|
|
9831
10876
|
|
|
9832
|
-
function GetTextureDisplayName(
|
|
9833
|
-
|
|
10877
|
+
function GetTextureDisplayName(record) {
|
|
10878
|
+
if (record.metadata.kind === "cube") {
|
|
10879
|
+
return `Texture ${record.ordinal} (Cube)`;
|
|
10880
|
+
}
|
|
10881
|
+
return typeof record.metadata.width === "number" && typeof record.metadata.height === "number"
|
|
10882
|
+
? `Texture ${record.ordinal} (${record.metadata.width} x ${record.metadata.height})`
|
|
10883
|
+
: `Texture ${record.ordinal}`;
|
|
9834
10884
|
}
|
|
9835
10885
|
const TextureExplorerServiceDefinition = {
|
|
9836
10886
|
friendlyName: "Babylon Lite Texture Explorer",
|
|
9837
|
-
consumes: [EngineExplorerServiceIdentity],
|
|
9838
|
-
factory: (engineExplorerService) => engineExplorerService.addRenderingContextNodeProvider({
|
|
10887
|
+
consumes: [EngineExplorerServiceIdentity, SceneResourceIndexServiceIdentity],
|
|
10888
|
+
factory: (engineExplorerService, resourceIndexService) => engineExplorerService.addRenderingContextNodeProvider({
|
|
9839
10889
|
order: 200,
|
|
9840
10890
|
predicate: IsSceneContext,
|
|
9841
|
-
getNodes: (scene) =>
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
|
|
10891
|
+
getNodes: (scene) => {
|
|
10892
|
+
const records = resourceIndexService.getSceneSnapshot(scene).textures;
|
|
10893
|
+
const recordsByEntity = new Map(records.map((record) => [record.entity, record]));
|
|
10894
|
+
return [
|
|
10895
|
+
CreateSceneExplorerSectionNode("textures", "Textures", records.map((record) => record.entity), (texture) => ({ name: GetTextureDisplayName(recordsByEntity.get(texture)) }), () => jsx(ImageRegular, { color: tokens.colorPaletteGrapeForeground2 })),
|
|
10896
|
+
];
|
|
10897
|
+
},
|
|
10898
|
+
getSnapshot: (scene) => resourceIndexService.getSceneSnapshot(scene).textures.map((record) => record.entity),
|
|
10899
|
+
onChanged: resourceIndexService.onChanged,
|
|
9845
10900
|
}),
|
|
9846
10901
|
};
|
|
9847
10902
|
|
|
@@ -9882,6 +10937,7 @@ function ShowInspector(engine, options = {}) {
|
|
|
9882
10937
|
engineContextServiceDefinition,
|
|
9883
10938
|
watcherServiceDefinition,
|
|
9884
10939
|
EngineExplorerServiceDefinition,
|
|
10940
|
+
SceneResourceIndexServiceDefinition,
|
|
9885
10941
|
MeshExplorerServiceDefinition,
|
|
9886
10942
|
CameraExplorerServiceDefinition,
|
|
9887
10943
|
LightExplorerServiceDefinition,
|
|
@@ -9890,6 +10946,7 @@ function ShowInspector(engine, options = {}) {
|
|
|
9890
10946
|
TextureExplorerServiceDefinition,
|
|
9891
10947
|
TextLayerExplorerServiceDefinition,
|
|
9892
10948
|
SpriteLayerExplorerServiceDefinition,
|
|
10949
|
+
AnimationGroupExplorerServiceDefinition,
|
|
9893
10950
|
PropertiesServiceDefinition,
|
|
9894
10951
|
EnginePropertiesServiceDefinition,
|
|
9895
10952
|
RenderingContextPropertiesServiceDefinition,
|
|
@@ -9902,12 +10959,14 @@ function ShowInspector(engine, options = {}) {
|
|
|
9902
10959
|
TexturePropertiesServiceDefinition,
|
|
9903
10960
|
TextLayerPropertiesServiceDefinition,
|
|
9904
10961
|
SpriteLayerPropertiesServiceDefinition,
|
|
10962
|
+
AnimationPropertiesServiceDefinition,
|
|
9905
10963
|
SettingsServiceDefinition,
|
|
9906
10964
|
watcherSettingsServiceDefinition,
|
|
9907
10965
|
ShellSettingsServiceDefinition,
|
|
9908
10966
|
watcherRefreshToolbarServiceDefinition,
|
|
9909
10967
|
SelectionServiceDefinition,
|
|
9910
10968
|
EngineSelectionServiceDefinition,
|
|
10969
|
+
PickingServiceDefinition,
|
|
9911
10970
|
];
|
|
9912
10971
|
return {
|
|
9913
10972
|
serviceDefinitions,
|
|
@@ -9917,5 +10976,5 @@ function ShowInspector(engine, options = {}) {
|
|
|
9917
10976
|
});
|
|
9918
10977
|
}
|
|
9919
10978
|
|
|
9920
|
-
export {
|
|
9921
|
-
//# sourceMappingURL=index-
|
|
10979
|
+
export { EntitySelector as $, Accordion as A, ButtonLine as B, ComputedProperty as C, DerivedProperty as D, BridgeCommandRegistryIdentity as E, BuiltInsExtensionFeed as F, GetAnimationFrameRate as G, Button as H, Checkbox as I, CheckboxPropertyLine as J, ChildWindow as K, Link as L, MessageBar as M, NumberInputPropertyLine as N, Collapse as O, PropertyLine as P, ComboBox as Q, ResourceSelector as R, ShellServiceIdentity as S, TextPropertyLine as T, ComboBoxPropertyLine as U, Vector2PropertyLine as V, ConstructorFactory as W, DraggableLine as X, Dropdown as Y, EngineContextIdentity as Z, EngineExplorerServiceIdentity as _, useWatcher as a, useTheme as a$, ErrorBoundary as a0, ExplorerServiceIdentity as a1, ExtensibleAccordion as a2, FileUploadLine as a3, GetPropertyDescriptor as a4, HexPropertyLine as a5, InfoLabel as a6, InterceptFunction as a7, InterceptProperty as a8, IsPropertyReadonly as a9, SpinButton as aA, SpinButtonPropertyLine as aB, StringDropdown as aC, Switch as aD, SyncedSliderInput as aE, TeachingMoment as aF, TextAreaPropertyLine as aG, TextInput as aH, Textarea as aI, Theme as aJ, ThemeServiceIdentity as aK, ToastProvider as aL, ToggleButton as aM, Tooltip as aN, UploadButton as aO, WatcherServiceIdentity as aP, useAngleConverters as aQ, useAsyncResource as aR, useEventListener as aS, useEventfulState as aT, useInterceptObservable as aU, useKeyListener as aV, useKeyState as aW, useObservableCollection as aX, useOrderedObservableCollection as aY, usePollingObservable as aZ, useResource as a_, LineContainer as aa, List as ab, MakeDialogTeachingMoment as ac, MakeLazyComponent as ad, MakeModularBridge as ae, MakeModularTool as af, MakePopoverTeachingMoment as ag, MakeTeachingMoment as ah, NumberDropdown as ai, ObservableCollection as aj, Pane as ak, PlaceholderPropertyLine as al, Popover as am, PositionedPopover as an, PropertiesServiceIdentity as ao, PropertyContext as ap, SearchBar as aq, SearchBox as ar, SelectionServiceDefinition as as, SelectionServiceIdentity as at, SettingsServiceIdentity as au, SettingsStore as av, SettingsStoreIdentity as aw, ShowInspector as ax, SidePaneContainer as ay, Slider as az, useWatchedValue as b, useThemeMode as b0, useToast as b1, SeekAnimationFrame as c, BoundProperty as d, SyncedSliderPropertyLine as e, SwitchPropertyLine as f, StringifiedPropertyLine as g, GetTargetedAnimationDisplayName as h, GetEntityAnimationGroups as i, GetEntityId as j, TextInputPropertyLine as k, Color3PropertyLine as l, NumberDropdownPropertyLine as m, StringDropdownPropertyLine as n, useObservableState as o, usePropertyChangedNotifier as p, GetMaterialOwningScenes as q, Color4PropertyLine as r, Vector4PropertyLine as s, Vector3PropertyLine as t, useExtensionManager as u, BooleanBadgePropertyLine as v, LinkPropertyLine as w, GetMaterialTopologyBindings as x, AccordionSection as y, AccordionSectionItem as z };
|
|
10980
|
+
//# sourceMappingURL=index-Cy8gzpYG.js.map
|