@babylonjs/inspector 8.44.1-preview → 8.45.0-preview
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/lib/{captureService-Bo4xI_X9.js → captureService-BRFdjxFs.js} +10 -2
- package/lib/{captureService-Bo4xI_X9.js.map → captureService-BRFdjxFs.js.map} +1 -1
- package/lib/{exportService-DCYVwNJE.js → exportService-bnHVeuTp.js} +10 -2
- package/lib/{exportService-DCYVwNJE.js.map → exportService-bnHVeuTp.js.map} +1 -1
- package/lib/{extensionsListService-BnPM7JOI.js → extensionsListService-CbClUfJa.js} +10 -2
- package/lib/{extensionsListService-BnPM7JOI.js.map → extensionsListService-CbClUfJa.js.map} +1 -1
- package/lib/{importService--DIvq_s3.js → importService-CGjLAv9b.js} +10 -2
- package/lib/{importService--DIvq_s3.js.map → importService-CGjLAv9b.js.map} +1 -1
- package/lib/{index-9CJtnfZ3.js → index-bFqtVcnb.js} +912 -121
- package/lib/index-bFqtVcnb.js.map +1 -0
- package/lib/index.d.ts +83 -34
- package/lib/index.js +9 -1
- package/lib/index.js.map +1 -1
- package/lib/{quickCreateToolsService-BFr5_q0T.js → quickCreateToolsService-B_KvGvkG.js} +10 -2
- package/lib/{quickCreateToolsService-BFr5_q0T.js.map → quickCreateToolsService-B_KvGvkG.js.map} +1 -1
- package/package.json +1 -1
- package/lib/index-9CJtnfZ3.js.map +0 -1
|
@@ -4,7 +4,7 @@ import { Color3, Color4 } from '@babylonjs/core/Maths/math.color.js';
|
|
|
4
4
|
import { Vector3, Quaternion, Matrix, Vector2, Vector4, TmpVectors } from '@babylonjs/core/Maths/math.vector.js';
|
|
5
5
|
import { Observable } from '@babylonjs/core/Misc/observable.js';
|
|
6
6
|
import { makeStyles, Link as Link$1, Body1, ToggleButton as ToggleButton$1, Button as Button$1, tokens, InfoLabel as InfoLabel$1, Body1Strong, Checkbox as Checkbox$1, mergeClasses, Accordion as Accordion$1, AccordionItem, AccordionHeader, Subtitle2Stronger, AccordionPanel, Divider, createLightTheme, createDarkTheme, FluentProvider, TeachingPopover, TeachingPopoverSurface, TeachingPopoverHeader, TeachingPopoverBody, Portal, RendererProvider, createDOMRenderer, Tooltip, Menu, MenuTrigger, SplitButton, MenuPopover, MenuList, MenuItem, Toolbar as Toolbar$1, ToolbarRadioButton, MenuGroup, MenuGroupHeader, SearchBox as SearchBox$1, FlatTree, FlatTreeItem, TreeItemLayout, MenuDivider, treeItemLevelToken, MenuItemCheckbox, Switch as Switch$1, PresenceBadge, useId, SpinButton as SpinButton$1, Slider, Input, Dropdown as Dropdown$1, Option, Popover as Popover$1, PopoverTrigger, PopoverSurface, ColorPicker, ColorArea, ColorSlider, AlphaSlider, ColorSwatch, MenuItemRadio, Dialog, DialogSurface, DialogBody, DialogTitle, DialogContent, DialogActions, List as List$1, ListItem, Spinner, Badge, MessageBar as MessageBar$1, MessageBarBody, MessageBarTitle, useComboboxFilter, Combobox, Textarea as Textarea$1, ToolbarButton, Label, ToolbarDivider, Field } from '@fluentui/react-components';
|
|
7
|
-
import { ChevronCircleRight16Regular, ChevronCircleRight20Regular, ChevronCircleDown16Regular, ChevronCircleDown20Regular, Copy16Regular, Copy20Regular, PanelLeftExpandRegular, PanelRightExpandRegular, PanelLeftContractRegular, PanelRightContractRegular, PictureInPictureEnterRegular, MoreHorizontalRegular, LayoutColumnTwoFocusLeftFilled, LayoutColumnTwoSplitLeftFocusTopLeftFilled, LayoutColumnTwoSplitLeftFocusBottomLeftFilled, LayoutColumnTwoFocusRightFilled, LayoutColumnTwoSplitRightFocusTopRightFilled, LayoutColumnTwoSplitRightFocusBottomRightFilled, DocumentTextRegular, createFluentIcon, FilterRegular, GlobeRegular, ArrowExpandAllRegular, ArrowCollapseAllRegular, CubeTreeRegular, BugRegular, SettingsRegular, ArrowUploadRegular, DataBarHorizontalRegular, WrenchRegular, WeatherSunnyRegular, WeatherMoonRegular, ErrorCircleRegular, ArrowRotateClockwiseRegular, ArrowExpandRegular, SelectObjectRegular, CubeRegular, SaveRegular, ArrowUndoRegular, BracesRegular, BracesDismiss16Regular, CopyRegular, DeleteRegular, EyeOffFilled, EyeFilled, ArrowMoveFilled, StopFilled, PlayFilled, EyeRegular, EyeOffRegular, LockOpenRegular, LockClosedRegular, ResizeRegular, ChevronUpRegular, ChevronDownRegular, ArrowResetRegular, CircleHalfFillRegular, EyedropperRegular, PaintBucketRegular, InkStrokeRegular, StackRegular, FilmstripRegular, PauseFilled, WeatherSunnyLowFilled, LayerRegular, FrameRegular, PlayRegular, AppGenericRegular, MyLocationRegular, CameraRegular, LightbulbRegular, BorderOutsideRegular, BorderNoneRegular, VideoFilled, VideoRegular, FlashlightRegular, FlashlightOffRegular, DropRegular, BlurRegular, PipelineRegular, PersonWalkingRegular, DataLineRegular, PersonSquareRegular, LayerDiagonalPersonRegular, ImageEditRegular, ImageRegular, TargetRegular, PersonFeedbackRegular, BranchRegular, DeleteFilled } from '@fluentui/react-icons';
|
|
7
|
+
import { ChevronCircleRight16Regular, ChevronCircleRight20Regular, ChevronCircleDown16Regular, ChevronCircleDown20Regular, Copy16Regular, Copy20Regular, PanelLeftExpandRegular, PanelRightExpandRegular, PanelLeftContractRegular, PanelRightContractRegular, PictureInPictureEnterRegular, MoreHorizontalRegular, LayoutColumnTwoFocusLeftFilled, LayoutColumnTwoSplitLeftFocusTopLeftFilled, LayoutColumnTwoSplitLeftFocusBottomLeftFilled, LayoutColumnTwoFocusRightFilled, LayoutColumnTwoSplitRightFocusTopRightFilled, LayoutColumnTwoSplitRightFocusBottomRightFilled, DocumentTextRegular, createFluentIcon, FilterRegular, GlobeRegular, ArrowExpandAllRegular, ArrowCollapseAllRegular, CubeTreeRegular, BugRegular, SettingsRegular, ArrowUploadRegular, DataBarHorizontalRegular, WrenchRegular, WeatherSunnyRegular, WeatherMoonRegular, ErrorCircleRegular, ArrowRotateClockwiseRegular, ArrowExpandRegular, SelectObjectRegular, CubeRegular, LinkDismissRegular, LinkEditRegular, SaveRegular, ArrowUndoRegular, BracesRegular, BracesDismiss16Regular, CopyRegular, DeleteRegular, EyeOffFilled, EyeFilled, ArrowMoveFilled, StopFilled, PlayFilled, EyeRegular, EyeOffRegular, LockOpenRegular, LockClosedRegular, ResizeRegular, ChevronUpRegular, ChevronDownRegular, ArrowResetRegular, CircleHalfFillRegular, EyedropperRegular, PaintBucketRegular, InkStrokeRegular, StackRegular, FilmstripRegular, PauseFilled, WeatherSunnyLowFilled, LayerRegular, FrameRegular, PlayRegular, AppGenericRegular, MyLocationRegular, CameraRegular, LightbulbRegular, BorderOutsideRegular, BorderNoneRegular, VideoFilled, VideoRegular, FlashlightRegular, FlashlightOffRegular, DropRegular, BlurRegular, PipelineRegular, PersonWalkingRegular, DataLineRegular, PersonSquareRegular, LayerDiagonalPersonRegular, ImageEditRegular, ImageRegular, TargetRegular, PersonFeedbackRegular, BranchRegular, DeleteFilled } from '@fluentui/react-icons';
|
|
8
8
|
import { Collapse as Collapse$1, Fade } from '@fluentui/react-motion-components-preview';
|
|
9
9
|
import '@babylonjs/core/Misc/typeStore.js';
|
|
10
10
|
import { useLocalStorage, useTernaryDarkMode } from 'usehooks-ts';
|
|
@@ -82,6 +82,14 @@ import { RenderingManager } from '@babylonjs/core/Rendering/renderingManager.js'
|
|
|
82
82
|
import '@babylonjs/core/Rendering/edgesRenderer.js';
|
|
83
83
|
import '@babylonjs/core/Rendering/outlineRenderer.js';
|
|
84
84
|
import { GaussianSplattingMesh } from '@babylonjs/core/Meshes/GaussianSplatting/gaussianSplattingMesh.js';
|
|
85
|
+
import { BoxParticleEmitter } from '@babylonjs/core/Particles/EmitterTypes/boxParticleEmitter.js';
|
|
86
|
+
import { ConeParticleEmitter } from '@babylonjs/core/Particles/EmitterTypes/coneParticleEmitter.js';
|
|
87
|
+
import { CylinderParticleEmitter } from '@babylonjs/core/Particles/EmitterTypes/cylinderParticleEmitter.js';
|
|
88
|
+
import { HemisphericParticleEmitter } from '@babylonjs/core/Particles/EmitterTypes/hemisphericParticleEmitter.js';
|
|
89
|
+
import { MeshParticleEmitter } from '@babylonjs/core/Particles/EmitterTypes/meshParticleEmitter.js';
|
|
90
|
+
import { PointParticleEmitter } from '@babylonjs/core/Particles/EmitterTypes/pointParticleEmitter.js';
|
|
91
|
+
import { SphereParticleEmitter } from '@babylonjs/core/Particles/EmitterTypes/sphereParticleEmitter.js';
|
|
92
|
+
import { ParticleHelper } from '@babylonjs/core/Particles/particleHelper.js';
|
|
85
93
|
import { FactorGradient, Color3Gradient, ColorGradient } from '@babylonjs/core/Misc/gradients.js';
|
|
86
94
|
import { GradientBlockColorStep } from '@babylonjs/core/Materials/Node/Blocks/gradientBlock.js';
|
|
87
95
|
import { Attractor } from '@babylonjs/core/Particles/attractor.js';
|
|
@@ -566,20 +574,27 @@ function BoundPropertyCoreImpl(props, ref) {
|
|
|
566
574
|
// Hook the property, using the specific hook that also catches changes to nested properties as well (like x/y/z on a Vector3 for example).
|
|
567
575
|
const value = useSpecificProperty(target, propertyKey);
|
|
568
576
|
const convertedValue = convertTo ? convertTo(value) : value;
|
|
577
|
+
const onChange = useMemo(() => {
|
|
578
|
+
const propertyDescriptor = GetPropertyDescriptor(target, propertyKey)?.[1];
|
|
579
|
+
if (propertyDescriptor && (propertyDescriptor.set || propertyDescriptor.writable)) {
|
|
580
|
+
return (val) => {
|
|
581
|
+
const oldValue = target[propertyKey];
|
|
582
|
+
const newValue = convertFrom ? convertFrom(val) : val;
|
|
583
|
+
target[propertyKey] = newValue;
|
|
584
|
+
notifyPropertyChanged(target, propertyKey, oldValue, newValue);
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
return undefined;
|
|
588
|
+
}, [target, propertyKey, convertFrom, notifyPropertyChanged]);
|
|
569
589
|
const propsToSend = {
|
|
570
590
|
...rest,
|
|
571
591
|
ref,
|
|
572
592
|
value: convertedValue,
|
|
573
|
-
onChange
|
|
574
|
-
const oldValue = target[propertyKey];
|
|
575
|
-
const newValue = convertFrom ? convertFrom(val) : val;
|
|
576
|
-
target[propertyKey] = newValue;
|
|
577
|
-
notifyPropertyChanged(target, propertyKey, oldValue, newValue);
|
|
578
|
-
},
|
|
593
|
+
onChange,
|
|
579
594
|
};
|
|
580
595
|
return jsx(Component, { ...propsToSend });
|
|
581
596
|
};
|
|
582
|
-
}, [useSpecificProperty]);
|
|
597
|
+
}, [useSpecificProperty, notifyPropertyChanged]);
|
|
583
598
|
return jsx(SpecificComponent, { ...props });
|
|
584
599
|
}
|
|
585
600
|
const BoundPropertyCore = CreateGenericForwardRef(BoundPropertyCoreImpl);
|
|
@@ -659,10 +674,11 @@ function copyCommandToClipboard(strCommand) {
|
|
|
659
674
|
|
|
660
675
|
const ToolContext = createContext({ useFluent: false, disableCopy: false, toolName: "", size: undefined });
|
|
661
676
|
|
|
662
|
-
const Link = (props) => {
|
|
677
|
+
const Link = forwardRef((props, ref) => {
|
|
663
678
|
const { target, url, onLink, ...rest } = props;
|
|
664
|
-
return (jsxs(Link$1, { inline: true, target: target === "current" ? "_self" : "_blank", rel: "noopener noreferrer", href: url, onClick: onLink ?? undefined, ...rest, children: [props.children, jsx(Body1, { children: props.value })] }));
|
|
665
|
-
};
|
|
679
|
+
return (jsxs(Link$1, { ref: ref, inline: true, target: target === "current" ? "_self" : "_blank", rel: "noopener noreferrer", href: url, onClick: onLink ?? undefined, ...rest, children: [props.children, jsx(Body1, { wrap: false, truncate: true, children: props.value })] }));
|
|
680
|
+
});
|
|
681
|
+
Link.displayName = "Link";
|
|
666
682
|
|
|
667
683
|
/**
|
|
668
684
|
* Toggles between two states using a button with icons.
|
|
@@ -790,10 +806,18 @@ const usePropertyLineStyles = makeStyles({
|
|
|
790
806
|
},
|
|
791
807
|
rightContent: {
|
|
792
808
|
flex: "0 1 auto",
|
|
809
|
+
minWidth: 0,
|
|
810
|
+
overflow: "hidden",
|
|
793
811
|
display: "flex",
|
|
794
812
|
alignItems: "center",
|
|
795
813
|
justifyContent: "flex-end",
|
|
796
814
|
},
|
|
815
|
+
childWrapper: {
|
|
816
|
+
minWidth: 0,
|
|
817
|
+
overflow: "hidden",
|
|
818
|
+
textOverflow: "ellipsis",
|
|
819
|
+
whiteSpace: "nowrap",
|
|
820
|
+
},
|
|
797
821
|
infoPopup: {
|
|
798
822
|
whiteSpace: "normal",
|
|
799
823
|
wordBreak: "break-word",
|
|
@@ -841,7 +865,7 @@ const PropertyLine = forwardRef((props, ref) => {
|
|
|
841
865
|
cachedVal.current = props.value;
|
|
842
866
|
props.onChange(null);
|
|
843
867
|
}
|
|
844
|
-
}, title: "Toggle null state" })), processedChildren, onCopy && !disableCopy && (jsx(Button, { className: classes.copy, title: "Copy to clipboard", appearance: "transparent", icon: size === "small" ? Copy16Regular : Copy20Regular, onClick: () => copyCommandToClipboard(onCopy()) }))] })] }), expandedContent && (jsx(Collapse, { visible: !!expanded, children: jsx("div", { className: classes.expandedContentDiv, children: expandedContent }) }))] }));
|
|
868
|
+
}, title: "Toggle null state" })), jsx("div", { className: classes.childWrapper, children: processedChildren }), onCopy && !disableCopy && (jsx(Button, { className: classes.copy, title: "Copy to clipboard", appearance: "transparent", icon: size === "small" ? Copy16Regular : Copy20Regular, onClick: () => copyCommandToClipboard(onCopy()) }))] })] }), expandedContent && (jsx(Collapse, { visible: !!expanded, children: jsx("div", { className: classes.expandedContentDiv, children: expandedContent }) }))] }));
|
|
845
869
|
});
|
|
846
870
|
const useLineStyles = makeStyles({
|
|
847
871
|
container: {
|
|
@@ -892,7 +916,7 @@ const LinkToEntityPropertyLine = (props) => {
|
|
|
892
916
|
!linkedEntity.reservedDataStore?.hidden && jsx(LinkPropertyLine, { ...rest, value: linkedEntity.name, onLink: () => (selectionService.selectedEntity = linkedEntity) }));
|
|
893
917
|
};
|
|
894
918
|
|
|
895
|
-
const useStyles$
|
|
919
|
+
const useStyles$s = makeStyles({
|
|
896
920
|
accordion: {
|
|
897
921
|
overflowX: "hidden",
|
|
898
922
|
overflowY: "auto",
|
|
@@ -936,13 +960,13 @@ const useStyles$r = makeStyles({
|
|
|
936
960
|
});
|
|
937
961
|
const AccordionSection = (props) => {
|
|
938
962
|
AccordionSection.displayName = "AccordionSection";
|
|
939
|
-
const classes = useStyles$
|
|
963
|
+
const classes = useStyles$s();
|
|
940
964
|
return jsx("div", { className: classes.panelDiv, children: props.children });
|
|
941
965
|
};
|
|
942
966
|
const StringAccordion = Accordion$1;
|
|
943
967
|
const Accordion = forwardRef((props, ref) => {
|
|
944
968
|
Accordion.displayName = "Accordion";
|
|
945
|
-
const classes = useStyles$
|
|
969
|
+
const classes = useStyles$s();
|
|
946
970
|
const { size } = useContext(ToolContext);
|
|
947
971
|
const { children, highlightSections, ...rest } = props;
|
|
948
972
|
const validChildren = useMemo(() => {
|
|
@@ -1073,7 +1097,7 @@ const CompactModeContextProvider = (props) => {
|
|
|
1073
1097
|
function AsReadonlyArray(array) {
|
|
1074
1098
|
return array;
|
|
1075
1099
|
}
|
|
1076
|
-
const useStyles$
|
|
1100
|
+
const useStyles$r = makeStyles({
|
|
1077
1101
|
rootDiv: {
|
|
1078
1102
|
flex: 1,
|
|
1079
1103
|
overflow: "hidden",
|
|
@@ -1082,7 +1106,7 @@ const useStyles$q = makeStyles({
|
|
|
1082
1106
|
},
|
|
1083
1107
|
});
|
|
1084
1108
|
function ExtensibleAccordion(props) {
|
|
1085
|
-
const classes = useStyles$
|
|
1109
|
+
const classes = useStyles$r();
|
|
1086
1110
|
const { children, sections, sectionContent, context, sectionsRef } = props;
|
|
1087
1111
|
const defaultSections = useMemo(() => {
|
|
1088
1112
|
const defaultSections = [];
|
|
@@ -1187,7 +1211,7 @@ function ExtensibleAccordion(props) {
|
|
|
1187
1211
|
})] }) })) }));
|
|
1188
1212
|
}
|
|
1189
1213
|
|
|
1190
|
-
const useStyles$
|
|
1214
|
+
const useStyles$q = makeStyles({
|
|
1191
1215
|
paneRootDiv: {
|
|
1192
1216
|
display: "flex",
|
|
1193
1217
|
flex: 1,
|
|
@@ -1200,7 +1224,7 @@ const useStyles$p = makeStyles({
|
|
|
1200
1224
|
*/
|
|
1201
1225
|
const SidePaneContainer = forwardRef((props, ref) => {
|
|
1202
1226
|
const { className, ...rest } = props;
|
|
1203
|
-
const classes = useStyles$
|
|
1227
|
+
const classes = useStyles$q();
|
|
1204
1228
|
return (jsx("div", { className: mergeClasses(classes.paneRootDiv, className), ref: ref, ...rest, children: props.children }));
|
|
1205
1229
|
});
|
|
1206
1230
|
|
|
@@ -1266,7 +1290,7 @@ const Theme = (props) => {
|
|
|
1266
1290
|
return (jsx(FluentProvider, { theme: isDarkMode !== invert ? DarkTheme : LightTheme, applyStylesToPortals: applyStylesToPortals, ...rest, children: props.children }));
|
|
1267
1291
|
};
|
|
1268
1292
|
|
|
1269
|
-
const useStyles$
|
|
1293
|
+
const useStyles$p = makeStyles({
|
|
1270
1294
|
extensionTeachingPopover: {
|
|
1271
1295
|
maxWidth: "320px",
|
|
1272
1296
|
},
|
|
@@ -1277,7 +1301,7 @@ const useStyles$o = makeStyles({
|
|
|
1277
1301
|
* @returns The teaching moment popover.
|
|
1278
1302
|
*/
|
|
1279
1303
|
const TeachingMoment = ({ shouldDisplay, positioningRef, onOpenChange, title, description }) => {
|
|
1280
|
-
const classes = useStyles$
|
|
1304
|
+
const classes = useStyles$p();
|
|
1281
1305
|
return (jsx(TeachingPopover, { appearance: "brand", open: shouldDisplay, positioning: { positioningRef }, onOpenChange: onOpenChange, children: jsxs(TeachingPopoverSurface, { className: classes.extensionTeachingPopover, children: [jsx(TeachingPopoverHeader, { children: title }), jsx(TeachingPopoverBody, { children: description })] }) }));
|
|
1282
1306
|
};
|
|
1283
1307
|
|
|
@@ -1532,13 +1556,13 @@ function ConstructorFactory(constructor) {
|
|
|
1532
1556
|
return (...args) => new constructor(...args);
|
|
1533
1557
|
}
|
|
1534
1558
|
|
|
1535
|
-
const useStyles$
|
|
1559
|
+
const useStyles$o = makeStyles({
|
|
1536
1560
|
placeholderDiv: {
|
|
1537
1561
|
padding: `${tokens.spacingVerticalM} ${tokens.spacingHorizontalM}`,
|
|
1538
1562
|
},
|
|
1539
1563
|
});
|
|
1540
1564
|
const PropertiesPane = (props) => {
|
|
1541
|
-
const classes = useStyles$
|
|
1565
|
+
const classes = useStyles$o();
|
|
1542
1566
|
const entity = props.context;
|
|
1543
1567
|
return entity != null ? (jsx(ExtensibleAccordion, { ...props })) : (jsx("div", { className: classes.placeholderDiv, children: jsx(Body1Strong, { italic: true, children: "No entity selected." }) }));
|
|
1544
1568
|
};
|
|
@@ -1563,7 +1587,7 @@ function ToFeaturesString(options) {
|
|
|
1563
1587
|
features.push({ key: "location", value: "no" });
|
|
1564
1588
|
return features.map((feature) => `${feature.key}=${feature.value}`).join(",");
|
|
1565
1589
|
}
|
|
1566
|
-
const useStyles$
|
|
1590
|
+
const useStyles$n = makeStyles({
|
|
1567
1591
|
container: {
|
|
1568
1592
|
display: "flex",
|
|
1569
1593
|
flexGrow: 1,
|
|
@@ -1578,7 +1602,7 @@ const useStyles$m = makeStyles({
|
|
|
1578
1602
|
*/
|
|
1579
1603
|
const ChildWindow = (props) => {
|
|
1580
1604
|
const { id, children, onOpenChange, imperativeRef: imperativeRef } = props;
|
|
1581
|
-
const classes = useStyles$
|
|
1605
|
+
const classes = useStyles$n();
|
|
1582
1606
|
const [windowState, setWindowState] = useState();
|
|
1583
1607
|
const [childWindow, setChildWindow] = useState();
|
|
1584
1608
|
const storageKey = id ? `Babylon/Settings/ChildWindow/${id}/Bounds` : null;
|
|
@@ -1790,7 +1814,7 @@ function useResizeHandle(params) {
|
|
|
1790
1814
|
|
|
1791
1815
|
const RootComponentServiceIdentity = Symbol("RootComponent");
|
|
1792
1816
|
const ShellServiceIdentity = Symbol("ShellService");
|
|
1793
|
-
const useStyles$
|
|
1817
|
+
const useStyles$m = makeStyles({
|
|
1794
1818
|
mainView: {
|
|
1795
1819
|
flex: 1,
|
|
1796
1820
|
display: "flex",
|
|
@@ -1976,12 +2000,12 @@ const DockMenu = (props) => {
|
|
|
1976
2000
|
};
|
|
1977
2001
|
const PaneHeader = (props) => {
|
|
1978
2002
|
const { id, title, dockOptions } = props;
|
|
1979
|
-
const classes = useStyles$
|
|
2003
|
+
const classes = useStyles$m();
|
|
1980
2004
|
return (jsx(Theme, { invert: true, children: jsxs("div", { className: classes.paneHeaderDiv, children: [jsx(Subtitle2Stronger, { className: classes.paneHeaderText, children: title }), jsx(DockMenu, { sidePaneId: id, dockOptions: dockOptions, children: jsx(Button$1, { className: classes.paneHeaderButton, appearance: "transparent", icon: jsx(MoreHorizontalRegular, {}) }) })] }) }));
|
|
1981
2005
|
};
|
|
1982
2006
|
// This is a wrapper for an item in a toolbar that simply adds a teaching moment, which is useful for dynamically added items, possibly from extensions.
|
|
1983
2007
|
const ToolbarItem = ({ verticalLocation, horizontalLocation, id, component: Component, displayName: displayName, suppressTeachingMoment }) => {
|
|
1984
|
-
const classes = useStyles$
|
|
2008
|
+
const classes = useStyles$m();
|
|
1985
2009
|
const useTeachingMoment = useMemo(() => MakePopoverTeachingMoment(`Bar/${verticalLocation}/${horizontalLocation}/${displayName ?? id}`), [displayName, id]);
|
|
1986
2010
|
const teachingMoment = useTeachingMoment(suppressTeachingMoment);
|
|
1987
2011
|
return (jsxs(Fragment, { children: [jsx(TeachingMoment, { ...teachingMoment, shouldDisplay: teachingMoment.shouldDisplay && !suppressTeachingMoment, title: displayName ?? "Extension", description: `The "${displayName ?? id}" extension can be accessed here.` }), jsx("div", { className: classes.barItem, ref: teachingMoment.targetRef, children: jsx(Component, {}) })] }));
|
|
@@ -1989,7 +2013,7 @@ const ToolbarItem = ({ verticalLocation, horizontalLocation, id, component: Comp
|
|
|
1989
2013
|
// TODO: Handle overflow, possibly via https://react.fluentui.dev/?path=/docs/components-overflow--docs with priority.
|
|
1990
2014
|
// This component just renders a toolbar with left aligned toolbar items on the left and right aligned toolbar items on the right.
|
|
1991
2015
|
const Toolbar = ({ location, components }) => {
|
|
1992
|
-
const classes = useStyles$
|
|
2016
|
+
const classes = useStyles$m();
|
|
1993
2017
|
const leftComponents = useMemo(() => components.filter((entry) => entry.horizontalLocation === "left"), [components]);
|
|
1994
2018
|
const rightComponents = useMemo(() => components.filter((entry) => entry.horizontalLocation === "right"), [components]);
|
|
1995
2019
|
return (jsx(Fragment, { children: components.length > 0 && (jsxs("div", { className: `${classes.bar} ${location === "top" ? classes.barTop : null}`, children: [jsx("div", { className: classes.barLeft, children: leftComponents.map((entry) => (jsx(ToolbarItem, { verticalLocation: location, horizontalLocation: entry.horizontalLocation, id: entry.key, component: entry.component, displayName: entry.displayName, suppressTeachingMoment: entry.suppressTeachingMoment }, entry.key))) }), jsx("div", { className: classes.barRight, children: rightComponents.map((entry) => (jsx(ToolbarItem, { verticalLocation: location, horizontalLocation: entry.horizontalLocation, id: entry.key, component: entry.component, displayName: entry.displayName, suppressTeachingMoment: entry.suppressTeachingMoment }, entry.key))) })] })) }));
|
|
@@ -1999,7 +2023,7 @@ const SidePaneTab = (props) => {
|
|
|
1999
2023
|
const { location, id, isSelected, dockOptions,
|
|
2000
2024
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
2001
2025
|
icon: Icon, title, suppressTeachingMoment, } = props;
|
|
2002
|
-
const classes = useStyles$
|
|
2026
|
+
const classes = useStyles$m();
|
|
2003
2027
|
const useTeachingMoment = useMemo(() => MakePopoverTeachingMoment(`Pane/${location}/${title ?? id}`), [title, id]);
|
|
2004
2028
|
const teachingMoment = useTeachingMoment(suppressTeachingMoment);
|
|
2005
2029
|
const tabClass = mergeClasses(classes.tab, isSelected ? undefined : classes.unselectedTab);
|
|
@@ -2012,7 +2036,7 @@ const SidePaneTab = (props) => {
|
|
|
2012
2036
|
// In "compact" mode, the tab list is integrated into the pane itself.
|
|
2013
2037
|
// In "full" mode, the returned tab list is later injected into the toolbar.
|
|
2014
2038
|
function usePane(location, defaultWidth, minWidth, sidePanes, onSelectSidePane, dockOperations, toolbarMode, topBarItems, bottomBarItems) {
|
|
2015
|
-
const classes = useStyles$
|
|
2039
|
+
const classes = useStyles$m();
|
|
2016
2040
|
const [topSelectedTab, setTopSelectedTab] = useState();
|
|
2017
2041
|
const [bottomSelectedTab, setBottomSelectedTab] = useState();
|
|
2018
2042
|
const [collapsed, setCollapsed] = useState(false);
|
|
@@ -2203,7 +2227,7 @@ function MakeShellServiceDefinition({ leftPaneDefaultWidth = 350, leftPaneMinWid
|
|
|
2203
2227
|
undock: () => onDockChanged.notifyObservers({ location: "right", dock: false }),
|
|
2204
2228
|
};
|
|
2205
2229
|
const rootComponent = () => {
|
|
2206
|
-
const classes = useStyles$
|
|
2230
|
+
const classes = useStyles$m();
|
|
2207
2231
|
const [sidePaneDockOverrides, setSidePaneDockOverrides] = useSidePaneDockOverrides();
|
|
2208
2232
|
// This function returns a promise that resolves after the dock change takes effect so that
|
|
2209
2233
|
// we can then select the re-docked pane.
|
|
@@ -2638,7 +2662,7 @@ function useCommandContextMenuState(commands) {
|
|
|
2638
2662
|
checkmark: command.icon ? null : undefined, icon: command.icon ? jsx(command.icon, {}) : undefined, name: "toggleCommands", value: command.displayName, children: command.displayName }, command.displayName)));
|
|
2639
2663
|
return [checkedContextMenuItems, onContextMenuCheckedValueChange, contextMenuItems];
|
|
2640
2664
|
}
|
|
2641
|
-
const useStyles$
|
|
2665
|
+
const useStyles$l = makeStyles({
|
|
2642
2666
|
rootDiv: {
|
|
2643
2667
|
flex: 1,
|
|
2644
2668
|
overflow: "hidden",
|
|
@@ -2706,14 +2730,14 @@ function MakeInlineCommandElement(command, isPlaceholder) {
|
|
|
2706
2730
|
}
|
|
2707
2731
|
const SceneTreeItem = (props) => {
|
|
2708
2732
|
const { isSelected, select } = props;
|
|
2709
|
-
const classes = useStyles$
|
|
2733
|
+
const classes = useStyles$l();
|
|
2710
2734
|
const [compactMode] = useCompactMode();
|
|
2711
2735
|
const treeItemLayoutClass = mergeClasses(classes.sceneTreeItemLayout, compactMode ? classes.treeItemLayoutCompact : undefined);
|
|
2712
2736
|
return (jsx(FlatTreeItem, { value: "scene", itemType: "leaf", parentValue: undefined, "aria-level": 1, "aria-setsize": 1, "aria-posinset": 1, onClick: select, children: jsx(TreeItemLayout, { iconBefore: jsx(GlobeRegular, {}), className: treeItemLayoutClass, style: isSelected ? { backgroundColor: tokens.colorNeutralBackground1Selected } : undefined, children: jsx(Body1Strong, { wrap: false, truncate: true, children: "Scene" }) }) }, "scene"));
|
|
2713
2737
|
};
|
|
2714
2738
|
const SectionTreeItem = (props) => {
|
|
2715
2739
|
const { section, isFiltering, commandProviders, expandAll, collapseAll } = props;
|
|
2716
|
-
const classes = useStyles$
|
|
2740
|
+
const classes = useStyles$l();
|
|
2717
2741
|
const [compactMode] = useCompactMode();
|
|
2718
2742
|
// Get the commands that apply to this section.
|
|
2719
2743
|
const commands = useResource(useCallback(() => {
|
|
@@ -2730,7 +2754,7 @@ const SectionTreeItem = (props) => {
|
|
|
2730
2754
|
};
|
|
2731
2755
|
const EntityTreeItem = (props) => {
|
|
2732
2756
|
const { entityItem, isSelected, select, isFiltering, commandProviders, expandAll, collapseAll } = props;
|
|
2733
|
-
const classes = useStyles$
|
|
2757
|
+
const classes = useStyles$l();
|
|
2734
2758
|
const [compactMode] = useCompactMode();
|
|
2735
2759
|
const hasChildren = !!entityItem.children?.length;
|
|
2736
2760
|
const displayInfo = useResource(useCallback(() => {
|
|
@@ -2823,7 +2847,7 @@ const EntityTreeItem = (props) => {
|
|
|
2823
2847
|
}, children: jsx(Body1, { wrap: false, truncate: true, children: name }) }) }, entityItem.entity.uniqueId) }), jsx(MenuPopover, { hidden: !hasChildren && contextMenuCommands.length === 0, children: jsxs(MenuList, { children: [hasChildren && (jsxs(Fragment, { children: [jsx(MenuItem, { icon: jsx(ArrowExpandAllRegular, {}), onClick: expandAll, children: jsx(Body1, { children: "Expand All" }) }), jsx(MenuItem, { icon: jsx(ArrowCollapseAllRegular, {}), onClick: collapseAll, children: jsx(Body1, { children: "Collapse All" }) })] })), hasChildren && contextMenuCommands.length > 0 && jsx(MenuDivider, {}), contextMenuItems] }) })] }));
|
|
2824
2848
|
};
|
|
2825
2849
|
const SceneExplorer = (props) => {
|
|
2826
|
-
const classes = useStyles$
|
|
2850
|
+
const classes = useStyles$l();
|
|
2827
2851
|
const { sections, entityCommandProviders, sectionCommandProviders, scene, selectedEntity } = props;
|
|
2828
2852
|
const [openItems, setOpenItems] = useState(new Set());
|
|
2829
2853
|
const [sceneVersion, setSceneVersion] = useState(0);
|
|
@@ -3618,14 +3642,14 @@ const TextPropertyLine = (props) => {
|
|
|
3618
3642
|
return (jsx(PropertyLine, { ...props, children: jsx(Body1, { title: title, children: value }) }));
|
|
3619
3643
|
};
|
|
3620
3644
|
|
|
3621
|
-
const useStyles$
|
|
3645
|
+
const useStyles$k = makeStyles({
|
|
3622
3646
|
pinnedStatsPane: {
|
|
3623
3647
|
flex: "0 1 auto",
|
|
3624
3648
|
paddingBottom: tokens.spacingHorizontalM,
|
|
3625
3649
|
},
|
|
3626
3650
|
});
|
|
3627
3651
|
const StatsPane = (props) => {
|
|
3628
|
-
const classes = useStyles$
|
|
3652
|
+
const classes = useStyles$k();
|
|
3629
3653
|
const scene = props.context;
|
|
3630
3654
|
const engine = scene.getEngine();
|
|
3631
3655
|
const fps = useObservableState(() => Math.round(engine.getFps()), engine.onBeginFrameObservable);
|
|
@@ -3803,7 +3827,7 @@ const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspector", [
|
|
|
3803
3827
|
keywords: ["export", "gltf", "glb", "babylon", "exporter", "tools"],
|
|
3804
3828
|
...BabylonWebResources,
|
|
3805
3829
|
author: { name: "Alex Chuber", forumUserName: "alexchuber" },
|
|
3806
|
-
getExtensionModuleAsync: async () => await import('./exportService-
|
|
3830
|
+
getExtensionModuleAsync: async () => await import('./exportService-bnHVeuTp.js'),
|
|
3807
3831
|
},
|
|
3808
3832
|
{
|
|
3809
3833
|
name: "Capture Tools",
|
|
@@ -3811,7 +3835,7 @@ const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspector", [
|
|
|
3811
3835
|
keywords: ["capture", "screenshot", "gif", "video", "tools"],
|
|
3812
3836
|
...BabylonWebResources,
|
|
3813
3837
|
author: { name: "Alex Chuber", forumUserName: "alexchuber" },
|
|
3814
|
-
getExtensionModuleAsync: async () => await import('./captureService-
|
|
3838
|
+
getExtensionModuleAsync: async () => await import('./captureService-BRFdjxFs.js'),
|
|
3815
3839
|
},
|
|
3816
3840
|
{
|
|
3817
3841
|
name: "Import Tools",
|
|
@@ -3819,7 +3843,7 @@ const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspector", [
|
|
|
3819
3843
|
keywords: ["import", "tools"],
|
|
3820
3844
|
...BabylonWebResources,
|
|
3821
3845
|
author: { name: "Alex Chuber", forumUserName: "alexchuber" },
|
|
3822
|
-
getExtensionModuleAsync: async () => await import('./importService
|
|
3846
|
+
getExtensionModuleAsync: async () => await import('./importService-CGjLAv9b.js'),
|
|
3823
3847
|
},
|
|
3824
3848
|
{
|
|
3825
3849
|
name: "Quick Creation Tools (Preview)",
|
|
@@ -3827,7 +3851,7 @@ const DefaultInspectorExtensionFeed = new BuiltInsExtensionFeed("Inspector", [
|
|
|
3827
3851
|
keywords: ["creation", "tools"],
|
|
3828
3852
|
...BabylonWebResources,
|
|
3829
3853
|
author: { name: "Babylon.js", forumUserName: "" },
|
|
3830
|
-
getExtensionModuleAsync: async () => await import('./quickCreateToolsService-
|
|
3854
|
+
getExtensionModuleAsync: async () => await import('./quickCreateToolsService-B_KvGvkG.js'),
|
|
3831
3855
|
},
|
|
3832
3856
|
]);
|
|
3833
3857
|
|
|
@@ -4045,7 +4069,7 @@ const Dropdown = (props) => {
|
|
|
4045
4069
|
const NumberDropdown = Dropdown;
|
|
4046
4070
|
const StringDropdown = Dropdown;
|
|
4047
4071
|
|
|
4048
|
-
const useStyles$
|
|
4072
|
+
const useStyles$j = makeStyles({
|
|
4049
4073
|
surface: {
|
|
4050
4074
|
maxWidth: "400px",
|
|
4051
4075
|
},
|
|
@@ -4060,7 +4084,7 @@ const useStyles$i = makeStyles({
|
|
|
4060
4084
|
const Popover = forwardRef((props, ref) => {
|
|
4061
4085
|
const { children } = props;
|
|
4062
4086
|
const [popoverOpen, setPopoverOpen] = useState(false);
|
|
4063
|
-
const classes = useStyles$
|
|
4087
|
+
const classes = useStyles$j();
|
|
4064
4088
|
return (jsxs(Popover$1, { open: popoverOpen, onOpenChange: (_, data) => setPopoverOpen(data.open), positioning: {
|
|
4065
4089
|
align: "start",
|
|
4066
4090
|
overflowBoundary: document.body,
|
|
@@ -4269,7 +4293,7 @@ const ColorPropertyLine = forwardRef((props, ref) => {
|
|
|
4269
4293
|
const Color3PropertyLine = ColorPropertyLine;
|
|
4270
4294
|
const Color4PropertyLine = ColorPropertyLine;
|
|
4271
4295
|
|
|
4272
|
-
const useStyles$
|
|
4296
|
+
const useStyles$i = makeStyles({
|
|
4273
4297
|
dropdown: {
|
|
4274
4298
|
...UniformWidthStyling,
|
|
4275
4299
|
},
|
|
@@ -4281,7 +4305,7 @@ const useStyles$h = makeStyles({
|
|
|
4281
4305
|
*/
|
|
4282
4306
|
const DropdownPropertyLine = forwardRef((props, ref) => {
|
|
4283
4307
|
DropdownPropertyLine.displayName = "DropdownPropertyLine";
|
|
4284
|
-
const classes = useStyles$
|
|
4308
|
+
const classes = useStyles$i();
|
|
4285
4309
|
return (jsx(PropertyLine, { ...props, ref: ref, children: jsx(Dropdown, { ...props, className: classes.dropdown }) }));
|
|
4286
4310
|
});
|
|
4287
4311
|
/**
|
|
@@ -4855,7 +4879,7 @@ class ServiceContainer {
|
|
|
4855
4879
|
}
|
|
4856
4880
|
}
|
|
4857
4881
|
|
|
4858
|
-
const useStyles$
|
|
4882
|
+
const useStyles$h = makeStyles({
|
|
4859
4883
|
themeButton: {
|
|
4860
4884
|
margin: 0,
|
|
4861
4885
|
},
|
|
@@ -4874,7 +4898,7 @@ const ThemeSelectorServiceDefinition = {
|
|
|
4874
4898
|
suppressTeachingMoment: true,
|
|
4875
4899
|
order: -300,
|
|
4876
4900
|
component: () => {
|
|
4877
|
-
const classes = useStyles$
|
|
4901
|
+
const classes = useStyles$h();
|
|
4878
4902
|
const { isDarkMode, themeMode, setThemeMode } = useThemeMode();
|
|
4879
4903
|
const onSelectedThemeChange = useCallback((e, data) => {
|
|
4880
4904
|
setThemeMode(data.checkedItems.includes("System") ? "system" : data.checkedItems[0].toLocaleLowerCase());
|
|
@@ -4891,7 +4915,7 @@ const ThemeSelectorServiceDefinition = {
|
|
|
4891
4915
|
},
|
|
4892
4916
|
};
|
|
4893
4917
|
|
|
4894
|
-
const useStyles$
|
|
4918
|
+
const useStyles$g = makeStyles({
|
|
4895
4919
|
app: {
|
|
4896
4920
|
colorScheme: "light dark",
|
|
4897
4921
|
flexGrow: 1,
|
|
@@ -4928,7 +4952,7 @@ function MakeModularTool(options) {
|
|
|
4928
4952
|
SetThemeMode(themeMode);
|
|
4929
4953
|
}
|
|
4930
4954
|
const modularToolRootComponent = () => {
|
|
4931
|
-
const classes = useStyles$
|
|
4955
|
+
const classes = useStyles$g();
|
|
4932
4956
|
const [extensionManagerContext, setExtensionManagerContext] = useState();
|
|
4933
4957
|
const [requiredExtensions, setRequiredExtensions] = useState();
|
|
4934
4958
|
const [requiredExtensionsDeferred, setRequiredExtensionsDeferred] = useState();
|
|
@@ -4954,7 +4978,7 @@ function MakeModularTool(options) {
|
|
|
4954
4978
|
});
|
|
4955
4979
|
// Register the extension list service (for browsing/installing extensions) if extension feeds are provided.
|
|
4956
4980
|
if (extensionFeeds.length > 0) {
|
|
4957
|
-
const { ExtensionListServiceDefinition } = await import('./extensionsListService-
|
|
4981
|
+
const { ExtensionListServiceDefinition } = await import('./extensionsListService-CbClUfJa.js');
|
|
4958
4982
|
await serviceContainer.addServiceAsync(ExtensionListServiceDefinition);
|
|
4959
4983
|
}
|
|
4960
4984
|
// Register the theme selector service (for selecting the theme) if theming is configured.
|
|
@@ -5136,7 +5160,7 @@ const MeshIcon = createFluentIcon("Mesh", "16", '<path d="M14.03,3.54l-5.11-2.07
|
|
|
5136
5160
|
const TranslateIcon = createFluentIcon("Translate", "24", '<path d="M20.16,12.98l-2.75-2.75c-.29-.29-.77-.29-1.06,0-.29.29-.29.77,0,1.06l1.47,1.47h-6.69v-6.69l1.47,1.47c.29.29.77.29,1.06,0,.29-.29.29-.77,0-1.06l-2.75-2.75c-.14-.14-.33-.22-.53-.22s-.39.08-.53.22l-2.75,2.75c-.29.29-.29.77,0,1.06.29.29.77.29,1.06,0l1.47-1.47v7.13l-3.52,3.52v-2.08c0-.41-.34-.75-.75-.75s-.75.34-.75.75v3.89c0,.2.08.39.22.53.14.14.33.22.53.22h3.89c.41,0,.75-.34.75-.75s-.34-.75-.75-.75h-2.08s3.52-3.52,3.52-3.52h7.13l-1.47,1.47c-.29.29-.29.77,0,1.06s.77.29,1.06,0l2.75-2.75c.14-.14.22-.33.22-.53s-.08-.39-.22-.53Z" />');
|
|
5137
5161
|
const MaterialIcon = createFluentIcon("Material", "16", '<path d="M14.74,6.3c-.09-.36-.38-.64-.75-.72-.04-.09-.08-.18-.12-.27.1-.15.16-.32.16-.51,0-.18-.05-.34-.13-.48-1.23-1.97-3.41-3.28-5.9-3.28C4.16,1.04,1.04,4.16,1.04,7.99c0,.39.23.72.57.88.02.12.03.25.06.37-.18.18-.3.42-.3.7,0,.11.02.21.06.31.94,2.74,3.53,4.71,6.58,4.71,3.84,0,6.96-3.12,6.96-6.96,0-.59-.08-1.16-.22-1.7ZM2.07,8.58c-.02-.19-.03-.39-.03-.58,0-3.29,2.67-5.96,5.96-5.96,2.23,0,4.17,1.23,5.2,3.05.05.18-.07.45-.3.75-.57-.73-1.45-1.21-2.45-1.21-1.72,0-3.12,1.4-3.12,3.11,0,.33.07.65.16.95-3.05.82-5.17.52-5.42-.11ZM12.56,7.75c0,1.17-.95,2.11-2.11,2.11s-2.12-.95-2.12-2.11.95-2.11,2.12-2.11,2.11.95,2.11,2.11ZM8,13.96c-2.6,0-4.81-1.68-5.62-4.01.5.16,1.11.24,1.79.24,1.15,0,2.49-.22,3.79-.59.57.76,1.47,1.26,2.49,1.26,1.72,0,3.11-1.4,3.11-3.11,0-.34-.07-.65-.17-.96.13-.13.24-.26.34-.39.14.51.22,1.04.22,1.6,0,3.29-2.67,5.96-5.96,5.96Z"/>');
|
|
5138
5162
|
|
|
5139
|
-
const useStyles$
|
|
5163
|
+
const useStyles$f = makeStyles({
|
|
5140
5164
|
coordinatesModeButton: {
|
|
5141
5165
|
margin: `0 0 0 ${tokens.spacingHorizontalXS}`,
|
|
5142
5166
|
},
|
|
@@ -5146,7 +5170,7 @@ const useStyles$e = makeStyles({
|
|
|
5146
5170
|
});
|
|
5147
5171
|
const GizmoToolbar = (props) => {
|
|
5148
5172
|
const { scene, entity, gizmoService } = props;
|
|
5149
|
-
const classes = useStyles$
|
|
5173
|
+
const classes = useStyles$f();
|
|
5150
5174
|
const gizmoManager = useResource(useCallback(() => {
|
|
5151
5175
|
const utilityLayerRef = gizmoService.getUtilityLayer(scene);
|
|
5152
5176
|
const keepDepthUtilityLayerRef = gizmoService.getUtilityLayer(scene, "keepDepth");
|
|
@@ -5261,7 +5285,7 @@ const GizmoToolbarServiceDefinition = {
|
|
|
5261
5285
|
},
|
|
5262
5286
|
};
|
|
5263
5287
|
|
|
5264
|
-
const useStyles$
|
|
5288
|
+
const useStyles$e = makeStyles({
|
|
5265
5289
|
badge: {
|
|
5266
5290
|
margin: tokens.spacingHorizontalXXS,
|
|
5267
5291
|
fontFamily: "monospace",
|
|
@@ -5277,7 +5301,7 @@ const MiniStatsServiceDefinition = {
|
|
|
5277
5301
|
horizontalLocation: "right",
|
|
5278
5302
|
suppressTeachingMoment: true,
|
|
5279
5303
|
component: () => {
|
|
5280
|
-
const classes = useStyles$
|
|
5304
|
+
const classes = useStyles$e();
|
|
5281
5305
|
const scene = useObservableState(useCallback(() => sceneContext.currentScene, [sceneContext.currentScene]), sceneContext.currentSceneObservable);
|
|
5282
5306
|
const engine = scene?.getEngine();
|
|
5283
5307
|
const fps = useObservableState(useCallback(() => (engine ? Math.round(engine.getFps()) : null), [engine]), engine?.onBeginFrameObservable);
|
|
@@ -6085,7 +6109,7 @@ const CommonBlendModes = [
|
|
|
6085
6109
|
* The below ParticleSystem consts were defined before new Engine alpha blend modes were added, so we have to reference
|
|
6086
6110
|
* the ParticleSystem.FOO consts explicitly (as the underlying const values are different - they get mapped to engine consts within baseParticleSystem.ts)
|
|
6087
6111
|
*/
|
|
6088
|
-
[
|
|
6112
|
+
const BlendModeOptions = [
|
|
6089
6113
|
{ label: "Add", value: ParticleSystem.BLENDMODE_ADD },
|
|
6090
6114
|
{ label: "Multiply", value: ParticleSystem.BLENDMODE_MULTIPLY },
|
|
6091
6115
|
{ label: "Multiply Add", value: ParticleSystem.BLENDMODE_MULTIPLYADD },
|
|
@@ -6103,6 +6127,15 @@ const AlphaModeOptions = [
|
|
|
6103
6127
|
{ label: "Subtract", value: Constants.ALPHA_SUBTRACT },
|
|
6104
6128
|
{ label: "Multiply", value: Constants.ALPHA_MULTIPLY },
|
|
6105
6129
|
].concat(CommonBlendModes);
|
|
6130
|
+
/**
|
|
6131
|
+
* Used to populate the billboardMode dropdown for particle systems.
|
|
6132
|
+
*/
|
|
6133
|
+
const ParticleBillboardModeOptions = [
|
|
6134
|
+
{ label: "All", value: ParticleSystem.BILLBOARDMODE_ALL },
|
|
6135
|
+
{ label: "Y", value: ParticleSystem.BILLBOARDMODE_Y },
|
|
6136
|
+
{ label: "Stretched", value: ParticleSystem.BILLBOARDMODE_STRETCHED },
|
|
6137
|
+
{ label: "Stretched Local", value: ParticleSystem.BILLBOARDMODE_STRETCHED_LOCAL },
|
|
6138
|
+
];
|
|
6106
6139
|
|
|
6107
6140
|
const OrientationOptions = [
|
|
6108
6141
|
{ label: "Clockwise", value: Material.ClockWiseSideOrientation },
|
|
@@ -6247,7 +6280,7 @@ const PBRBaseMaterialSheenProperties = (props) => {
|
|
|
6247
6280
|
} }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Roughness", target: material.sheen, propertyKey: "_useRoughness" }), jsx(Collapse, { visible: useRoughness, children: jsx(BoundProperty, { nullable: true, component: SyncedSliderPropertyLine, label: "Roughness", target: material.sheen, propertyKey: "roughness", defaultValue: 0, min: 0, max: 1, step: 0.01 }) }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Use Roughness from Main Texture", target: material.sheen, propertyKey: "useRoughnessFromMainTexture" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Albedo Scaling", target: material.sheen, propertyKey: "albedoScaling" })] })] }));
|
|
6248
6281
|
};
|
|
6249
6282
|
|
|
6250
|
-
const useStyles$
|
|
6283
|
+
const useStyles$d = makeStyles({
|
|
6251
6284
|
root: {
|
|
6252
6285
|
display: "grid",
|
|
6253
6286
|
gridTemplateRows: "repeat(1fr)",
|
|
@@ -6263,6 +6296,11 @@ const useStyles$c = makeStyles({
|
|
|
6263
6296
|
input: {
|
|
6264
6297
|
minWidth: 0,
|
|
6265
6298
|
},
|
|
6299
|
+
listbox: {
|
|
6300
|
+
width: "fit-content",
|
|
6301
|
+
minWidth: "fit-content",
|
|
6302
|
+
maxWidth: "350px",
|
|
6303
|
+
},
|
|
6266
6304
|
});
|
|
6267
6305
|
/**
|
|
6268
6306
|
* Wrapper around a Fluent ComboBox that allows for filtering options.
|
|
@@ -6272,7 +6310,7 @@ const useStyles$c = makeStyles({
|
|
|
6272
6310
|
const ComboBox = (props) => {
|
|
6273
6311
|
ComboBox.displayName = "ComboBox";
|
|
6274
6312
|
const comboId = useId();
|
|
6275
|
-
const styles = useStyles$
|
|
6313
|
+
const styles = useStyles$d();
|
|
6276
6314
|
const { size } = useContext(ToolContext);
|
|
6277
6315
|
// Find the label for the current value
|
|
6278
6316
|
const getLabel = (value) => props.options.find((opt) => opt.value === value)?.label ?? "";
|
|
@@ -6292,9 +6330,25 @@ const ComboBox = (props) => {
|
|
|
6292
6330
|
setQuery(data.optionText ?? "");
|
|
6293
6331
|
data.optionValue && props.onChange(data.optionValue);
|
|
6294
6332
|
};
|
|
6295
|
-
return (jsxs("div", { className: styles.root, children: [jsx("label", { id: comboId, children: props.label }), jsx(Combobox, { size: size, root: { className: styles.comboBox }, input: { className: styles.input }, onOptionSelect: onOptionSelect, "aria-labelledby": comboId, placeholder: "Search..", onChange: (ev) => setQuery(ev.target.value), value: query, children: children })] }));
|
|
6333
|
+
return (jsxs("div", { className: styles.root, children: [jsx("label", { id: comboId, children: props.label }), jsx(Combobox, { 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 })] }));
|
|
6296
6334
|
};
|
|
6297
6335
|
|
|
6336
|
+
const useStyles$c = makeStyles({
|
|
6337
|
+
linkDiv: {
|
|
6338
|
+
display: "flex",
|
|
6339
|
+
flexDirection: "row",
|
|
6340
|
+
alignItems: "center",
|
|
6341
|
+
gap: tokens.spacingHorizontalS,
|
|
6342
|
+
minWidth: 0,
|
|
6343
|
+
overflow: "hidden",
|
|
6344
|
+
},
|
|
6345
|
+
link: {
|
|
6346
|
+
minWidth: 0,
|
|
6347
|
+
overflow: "hidden",
|
|
6348
|
+
textOverflow: "ellipsis",
|
|
6349
|
+
whiteSpace: "nowrap",
|
|
6350
|
+
},
|
|
6351
|
+
});
|
|
6298
6352
|
/**
|
|
6299
6353
|
* A generic primitive component with a ComboBox for selecting from a list of entities.
|
|
6300
6354
|
* Supports entities with duplicate names by using uniqueId for identity.
|
|
@@ -6302,7 +6356,9 @@ const ComboBox = (props) => {
|
|
|
6302
6356
|
* @returns EntitySelector component
|
|
6303
6357
|
*/
|
|
6304
6358
|
function EntitySelector(props) {
|
|
6305
|
-
const { value,
|
|
6359
|
+
const { value, onLink, getEntities, getName, filter, defaultValue } = props;
|
|
6360
|
+
const onChange = props.onChange;
|
|
6361
|
+
const classes = useStyles$c();
|
|
6306
6362
|
// Build options with uniqueId as key
|
|
6307
6363
|
const options = useMemo(() => {
|
|
6308
6364
|
return getEntities()
|
|
@@ -6313,13 +6369,27 @@ function EntitySelector(props) {
|
|
|
6313
6369
|
}))
|
|
6314
6370
|
.sort((a, b) => a.label.localeCompare(b.label));
|
|
6315
6371
|
}, [getEntities, getName, filter]);
|
|
6372
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
6316
6373
|
const handleEntitySelect = (key) => {
|
|
6317
6374
|
const entity = getEntities().find((e) => e.uniqueId.toString() === key);
|
|
6318
|
-
onChange(entity ?? null);
|
|
6375
|
+
onChange?.(entity ?? null);
|
|
6376
|
+
setIsEditing(false);
|
|
6319
6377
|
};
|
|
6320
6378
|
// Get current entity key for display
|
|
6321
6379
|
const currentKey = value ? value.uniqueId.toString() : "";
|
|
6322
|
-
|
|
6380
|
+
if (value && !isEditing) {
|
|
6381
|
+
// If there is a value and we are not editing, show the link view
|
|
6382
|
+
return (jsxs("div", { className: classes.linkDiv, children: [jsx(Tooltip, { content: getName(value), relationship: "label", children: jsx(Link, { className: classes.link, value: getName(value), onLink: () => onLink(value) }) }), onChange &&
|
|
6383
|
+
(defaultValue !== undefined ? (
|
|
6384
|
+
// If the defaultValue is specified, then allow resetting to the default
|
|
6385
|
+
jsx(Button, { icon: LinkDismissRegular, onClick: () => onChange(defaultValue) })) : (
|
|
6386
|
+
// Otherwise, just allow editing to a new value
|
|
6387
|
+
jsx(Button, { icon: LinkEditRegular, onClick: () => setIsEditing(true) })))] }));
|
|
6388
|
+
}
|
|
6389
|
+
else {
|
|
6390
|
+
// Otherwise, show the ComboBox for selection
|
|
6391
|
+
return jsx(ComboBox, { label: "", options: options, value: currentKey, onChange: handleEntitySelect });
|
|
6392
|
+
}
|
|
6323
6393
|
}
|
|
6324
6394
|
EntitySelector.displayName = "EntitySelector";
|
|
6325
6395
|
|
|
@@ -6336,6 +6406,19 @@ const MaterialSelector = (props) => {
|
|
|
6336
6406
|
return jsx(EntitySelector, { ...rest, getEntities: getMaterials, getName: getName });
|
|
6337
6407
|
};
|
|
6338
6408
|
|
|
6409
|
+
/**
|
|
6410
|
+
* A primitive component with a ComboBox for selecting from existing scene nodes.
|
|
6411
|
+
* @param props NodeSelectorProps
|
|
6412
|
+
* @returns NodeSelector component
|
|
6413
|
+
*/
|
|
6414
|
+
const NodeSelector = (props) => {
|
|
6415
|
+
NodeSelector.displayName = "NodeSelector";
|
|
6416
|
+
const { scene, ...rest } = props;
|
|
6417
|
+
const getNodes = useCallback(() => scene.getNodes(), [scene]);
|
|
6418
|
+
const getName = useCallback((node) => node.name, []);
|
|
6419
|
+
return jsx(EntitySelector, { ...rest, getEntities: getNodes, getName: getName });
|
|
6420
|
+
};
|
|
6421
|
+
|
|
6339
6422
|
/**
|
|
6340
6423
|
* A button that uploads a file and either:
|
|
6341
6424
|
* - Updates an existing Texture or CubeTexture via updateURL (if texture prop is provided)
|
|
@@ -6410,16 +6493,31 @@ const useStyles$b = makeStyles({
|
|
|
6410
6493
|
*/
|
|
6411
6494
|
const TextureSelector = (props) => {
|
|
6412
6495
|
TextureSelector.displayName = "TextureSelector";
|
|
6413
|
-
const { scene, cubeOnly, value, onChange } = props;
|
|
6496
|
+
const { scene, cubeOnly, value, onChange, onLink, defaultValue } = props;
|
|
6414
6497
|
const classes = useStyles$b();
|
|
6415
6498
|
const getTextures = useCallback(() => scene.textures, [scene.textures]);
|
|
6416
|
-
const getName = useCallback((texture) => texture.displayName || texture.name
|
|
6499
|
+
const getName = useCallback((texture) => texture.displayName || texture.name || `${texture.getClassName() || "Unnamed Texture"} (${texture.uniqueId})`, []);
|
|
6417
6500
|
const filter = useCallback((texture) => !cubeOnly || texture.isCube, [cubeOnly]);
|
|
6418
|
-
return (jsxs("div", { className: classes.container, children: [jsx(EntitySelector, { value: value, onChange: onChange, getEntities: getTextures, getName: getName, filter: filter }), jsx(TextureUpload, { scene: scene, onChange: onChange, cubeOnly: cubeOnly })] }));
|
|
6501
|
+
return (jsxs("div", { className: classes.container, children: [jsx(EntitySelector, { value: value, onChange: onChange, onLink: onLink, defaultValue: defaultValue, getEntities: getTextures, getName: getName, filter: filter }), !value && jsx(TextureUpload, { scene: scene, onChange: onChange, cubeOnly: cubeOnly })] }));
|
|
6502
|
+
};
|
|
6503
|
+
|
|
6504
|
+
/**
|
|
6505
|
+
* A primitive component with a ComboBox for selecting from existing scene skeletons.
|
|
6506
|
+
* @param props SkeletonSelectorProps
|
|
6507
|
+
* @returns SkeletonSelector component
|
|
6508
|
+
*/
|
|
6509
|
+
const SkeletonSelector = (props) => {
|
|
6510
|
+
SkeletonSelector.displayName = "SkeletonSelector";
|
|
6511
|
+
const { scene, ...rest } = props;
|
|
6512
|
+
const getSkeletons = useCallback(() => scene.skeletons, [scene.skeletons]);
|
|
6513
|
+
const getName = useCallback((skeleton) => skeleton.name, []);
|
|
6514
|
+
return jsx(EntitySelector, { ...rest, getEntities: getSkeletons, getName: getName });
|
|
6419
6515
|
};
|
|
6420
6516
|
|
|
6517
|
+
const NodeSelectorPropertyLine = (props) => jsx(PropertyLine, { ...props, children: jsx(NodeSelector, { ...props }) });
|
|
6421
6518
|
const MaterialSelectorPropertyLine = (props) => jsx(PropertyLine, { ...props, children: jsx(MaterialSelector, { ...props }) });
|
|
6422
6519
|
const TextureSelectorPropertyLine = (props) => jsx(PropertyLine, { ...props, children: jsx(TextureSelector, { ...props }) });
|
|
6520
|
+
const SkeletonSelectorPropertyLine = (props) => jsx(PropertyLine, { ...props, children: jsx(SkeletonSelector, { ...props }) });
|
|
6423
6521
|
|
|
6424
6522
|
/**
|
|
6425
6523
|
* Displays the lighting and color properties of a PBR material.
|
|
@@ -6436,9 +6534,10 @@ const PBRMaterialLightingAndColorProperties = (props) => {
|
|
|
6436
6534
|
* @returns A JSX element representing the texture channels.
|
|
6437
6535
|
*/
|
|
6438
6536
|
const PBRMaterialTextureProperties = (props) => {
|
|
6439
|
-
const { material } = props;
|
|
6537
|
+
const { material, selectionService } = props;
|
|
6440
6538
|
const scene = material.getScene();
|
|
6441
|
-
|
|
6539
|
+
const selectEntity = (entity) => (selectionService.selectedEntity = entity);
|
|
6540
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Albedo", target: material, propertyKey: "albedoTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Base Weight", target: material, propertyKey: "baseWeightTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Base Diffuse Roughness", target: material, propertyKey: "baseDiffuseRoughnessTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Metallic Roughness", target: material, propertyKey: "metallicTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Reflection", target: material, propertyKey: "reflectionTexture", scene: scene, cubeOnly: true, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Refraction", target: material, propertyKey: "refractionTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Reflectivity", target: material, propertyKey: "reflectivityTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Micro-surface", target: material, propertyKey: "microSurfaceTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Bump", target: material, propertyKey: "bumpTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Emissive", target: material, propertyKey: "emissiveTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Opacity", target: material, propertyKey: "opacityTexture", scene: scene, onLink: selectEntity, defaultValue: null }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Ambient", target: material, propertyKey: "ambientTexture", scene: scene, onLink: selectEntity, defaultValue: null }), "component=", TextureSelectorPropertyLine, jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Lightmap", target: material, propertyKey: "lightmapTexture", scene: scene, onLink: selectEntity, defaultValue: null })] }));
|
|
6442
6541
|
};
|
|
6443
6542
|
|
|
6444
6543
|
// TODO: ryamtrem / gehalper This function is temporal until there is a line control to handle texture links (similar to the old TextureLinkLineComponent)
|
|
@@ -6717,7 +6816,7 @@ const MaterialPropertiesServiceDefinition = {
|
|
|
6717
6816
|
content: [
|
|
6718
6817
|
{
|
|
6719
6818
|
section: "Textures",
|
|
6720
|
-
component: ({ context }) => jsx(PBRMaterialTextureProperties, { material: context }),
|
|
6819
|
+
component: ({ context }) => jsx(PBRMaterialTextureProperties, { material: context, selectionService: selectionService }),
|
|
6721
6820
|
},
|
|
6722
6821
|
{
|
|
6723
6822
|
section: "Lighting & Colors",
|
|
@@ -7008,12 +7107,10 @@ const MetadataPropertiesServiceDefinition = {
|
|
|
7008
7107
|
const AbstractMeshGeneralProperties = (props) => {
|
|
7009
7108
|
const { mesh, selectionService } = props;
|
|
7010
7109
|
// Use the observable to keep keep state up-to-date and re-render the component when it changes.
|
|
7011
|
-
const material = useObservableState(() => mesh.material, mesh.onMaterialChangedObservable);
|
|
7012
|
-
const skeleton = useProperty(mesh, "skeleton");
|
|
7013
7110
|
const isAnInstance = useProperty(mesh, "isAnInstance");
|
|
7014
7111
|
// TODO: Handle case where array is mutated
|
|
7015
7112
|
const subMeshes = useProperty(mesh, "subMeshes");
|
|
7016
|
-
return (jsxs(Fragment, { children: [jsx(StringifiedPropertyLine, { label: "Vertices", value: mesh.getTotalVertices() }), jsx(StringifiedPropertyLine, { label: "Faces", value: mesh.getTotalIndices() / 3 }), jsx(StringifiedPropertyLine, { label: "Sub-Meshes", value: subMeshes.length }), jsx(
|
|
7113
|
+
return (jsxs(Fragment, { children: [jsx(StringifiedPropertyLine, { label: "Vertices", value: mesh.getTotalVertices() }), jsx(StringifiedPropertyLine, { label: "Faces", value: mesh.getTotalIndices() / 3 }), jsx(StringifiedPropertyLine, { label: "Sub-Meshes", value: subMeshes.length }), jsx(BoundProperty, { defaultValue: null, component: SkeletonSelectorPropertyLine, label: "Skeleton", description: "The skeleton associated with the mesh.", target: mesh, propertyKey: "skeleton", scene: mesh.getScene(), onLink: (skeleton) => (selectionService.selectedEntity = skeleton) }), !mesh.isAnInstance && (jsx(BoundProperty, { defaultValue: null, component: MaterialSelectorPropertyLine, label: "Material", description: "The material used by the mesh.", target: mesh, propertyKey: "material", scene: mesh.getScene(), onLink: (material) => (selectionService.selectedEntity = material) })), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Is Pickable", target: mesh, propertyKey: "isPickable" }), isAnInstance && mesh instanceof InstancedMesh && (jsx(BoundProperty, { component: NodeSelectorPropertyLine, label: "Source", description: "The source mesh from which this instance was created.", target: mesh, propertyKey: "sourceMesh", scene: mesh.getScene(), onLink: (node) => (selectionService.selectedEntity = node) }))] }));
|
|
7017
7114
|
};
|
|
7018
7115
|
const AbstractMeshDisplayProperties = (props) => {
|
|
7019
7116
|
const { mesh } = props;
|
|
@@ -7294,9 +7391,8 @@ const GaussianSplattingDisplayProperties = (props) => {
|
|
|
7294
7391
|
|
|
7295
7392
|
const NodeGeneralProperties = (props) => {
|
|
7296
7393
|
const { node, selectionService } = props;
|
|
7297
|
-
const parent = useProperty(node, "parent");
|
|
7298
7394
|
const isEnabled = useObservableState(() => node.isEnabled(false), node.onEnabledStateChangedObservable);
|
|
7299
|
-
return (jsxs(Fragment, { children: [jsx(
|
|
7395
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NodeSelectorPropertyLine, label: "Parent", target: node, propertyKey: "parent", scene: node.getScene(), defaultValue: null, onLink: (parentNode) => (selectionService.selectedEntity = parentNode) }), jsx(SwitchPropertyLine, { label: "Is Enabled", description: "Whether the node is enabled or not.", value: isEnabled, onChange: (checked) => node.setEnabled(checked) }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Inherit Visibility", description: "Whether the node inherits visibility from its parent.", target: node, propertyKey: "inheritVisibility" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Is Visible", description: "Whether the node is visible or not.", target: node, propertyKey: "isVisible" })] }));
|
|
7300
7396
|
};
|
|
7301
7397
|
|
|
7302
7398
|
const NodePropertiesServiceDefinition = {
|
|
@@ -7679,80 +7775,776 @@ const AttractorList = (props) => {
|
|
|
7679
7775
|
} })] }));
|
|
7680
7776
|
};
|
|
7681
7777
|
|
|
7682
|
-
const
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7687
|
-
|
|
7688
|
-
|
|
7689
|
-
|
|
7690
|
-
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
|
|
7778
|
+
const SnippetDashboardStorageKey = "Babylon/InspectorV2/SnippetDashboard/ParticleSystems";
|
|
7779
|
+
function TryParseJsonString(value) {
|
|
7780
|
+
if (!value) {
|
|
7781
|
+
return undefined;
|
|
7782
|
+
}
|
|
7783
|
+
try {
|
|
7784
|
+
return JSON.parse(value);
|
|
7785
|
+
}
|
|
7786
|
+
catch {
|
|
7787
|
+
return undefined;
|
|
7788
|
+
}
|
|
7789
|
+
}
|
|
7790
|
+
function ParseJsonLoadContents(contents) {
|
|
7791
|
+
if (contents instanceof ArrayBuffer) {
|
|
7792
|
+
const decoder = new TextDecoder("utf-8");
|
|
7793
|
+
return TryParseJsonString(decoder.decode(contents)) ?? undefined;
|
|
7794
|
+
}
|
|
7795
|
+
if (typeof contents === "string") {
|
|
7796
|
+
return TryParseJsonString(contents) ?? undefined;
|
|
7797
|
+
}
|
|
7798
|
+
return undefined;
|
|
7799
|
+
}
|
|
7800
|
+
function NormalizeParticleSystemSerialization(rawData) {
|
|
7801
|
+
const jsonPayload = TryParseJsonString(rawData?.jsonPayload);
|
|
7802
|
+
const particleSystem = TryParseJsonString(jsonPayload?.particleSystem);
|
|
7803
|
+
return particleSystem ?? rawData;
|
|
7804
|
+
}
|
|
7805
|
+
function PersistSnippetId(snippetId) {
|
|
7806
|
+
// Persist snippet IDs locally for quick reuse.
|
|
7807
|
+
try {
|
|
7808
|
+
const existing = JSON.parse(localStorage.getItem(SnippetDashboardStorageKey) || "[]");
|
|
7809
|
+
const list = Array.isArray(existing) ? existing : [];
|
|
7810
|
+
if (!list.includes(snippetId)) {
|
|
7811
|
+
list.unshift(snippetId);
|
|
7812
|
+
}
|
|
7813
|
+
localStorage.setItem(SnippetDashboardStorageKey, JSON.stringify(list.slice(0, 50)));
|
|
7814
|
+
}
|
|
7815
|
+
catch {
|
|
7816
|
+
// Ignore storage failures.
|
|
7817
|
+
}
|
|
7818
|
+
}
|
|
7819
|
+
/**
|
|
7820
|
+
* Display general (high-level) information about a particle system.
|
|
7821
|
+
* @param props Component props.
|
|
7822
|
+
* @returns Render property lines.
|
|
7823
|
+
*/
|
|
7824
|
+
const ParticleSystemGeneralProperties = (props) => {
|
|
7696
7825
|
const { particleSystem: system } = props;
|
|
7697
|
-
const
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
|
|
7702
|
-
|
|
7703
|
-
|
|
7826
|
+
const scene = system.getScene();
|
|
7827
|
+
const isBillboardBased = useProperty(system, "isBillboardBased");
|
|
7828
|
+
const capacity = useObservableState(() => system.getCapacity());
|
|
7829
|
+
const activeCount = useObservableState(() => system.getActiveCount(), scene?.onBeforeRenderObservable);
|
|
7830
|
+
const isAlive = useObservableState(() => system.isAlive(), scene?.onBeforeRenderObservable);
|
|
7831
|
+
const isStopping = useObservableState(() => system.isStopping(), scene?.onBeforeRenderObservable);
|
|
7832
|
+
const snippetId = useProperty(system, "snippetId");
|
|
7833
|
+
const [stopRequested, setStopRequested] = useState(false);
|
|
7834
|
+
useEffect(() => {
|
|
7835
|
+
if (!stopRequested) {
|
|
7836
|
+
return;
|
|
7837
|
+
}
|
|
7838
|
+
// Clear stop flag once the system fully stops.
|
|
7839
|
+
if (!isAlive && !isStopping) {
|
|
7840
|
+
setStopRequested(false);
|
|
7841
|
+
}
|
|
7842
|
+
}, [stopRequested, isAlive, isStopping]);
|
|
7843
|
+
const applyParticleSystemJsonToSystem = useCallback((jsonObject) => {
|
|
7844
|
+
if (!scene) {
|
|
7845
|
+
alert("No scene available.");
|
|
7846
|
+
return;
|
|
7847
|
+
}
|
|
7848
|
+
const candidate = NormalizeParticleSystemSerialization(jsonObject);
|
|
7849
|
+
try {
|
|
7850
|
+
// Apply in-place to keep selection stable.
|
|
7851
|
+
ParticleSystem._Parse(candidate, system, scene, "");
|
|
7852
|
+
}
|
|
7853
|
+
catch (e) {
|
|
7854
|
+
alert("Failed to load particle system: " + e);
|
|
7855
|
+
}
|
|
7856
|
+
}, [scene, system]);
|
|
7857
|
+
const loadFromSnippetServer = useCallback(() => {
|
|
7858
|
+
if (!scene) {
|
|
7859
|
+
alert("No scene available.");
|
|
7860
|
+
return;
|
|
7861
|
+
}
|
|
7862
|
+
// Prompt for a snippet id (minimal UX).
|
|
7863
|
+
const requestedSnippetId = window.prompt("Please enter the snippet ID to use");
|
|
7864
|
+
const trimmed = requestedSnippetId?.trim();
|
|
7865
|
+
if (!trimmed) {
|
|
7866
|
+
return;
|
|
7867
|
+
}
|
|
7868
|
+
const request = new XMLHttpRequest();
|
|
7869
|
+
request.onreadystatechange = () => {
|
|
7870
|
+
if (request.readyState !== 4) {
|
|
7871
|
+
return;
|
|
7872
|
+
}
|
|
7873
|
+
if (request.status !== 200) {
|
|
7874
|
+
alert("Unable to load your particle system");
|
|
7875
|
+
return;
|
|
7876
|
+
}
|
|
7877
|
+
try {
|
|
7878
|
+
const responseObject = ParseJsonLoadContents(request.responseText);
|
|
7879
|
+
if (!responseObject) {
|
|
7880
|
+
alert("Unable to load your particle system");
|
|
7881
|
+
return;
|
|
7704
7882
|
}
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
|
|
7883
|
+
applyParticleSystemJsonToSystem(responseObject);
|
|
7884
|
+
system.snippetId = trimmed;
|
|
7885
|
+
}
|
|
7886
|
+
catch (e) {
|
|
7887
|
+
alert("Unable to load your particle system: " + e);
|
|
7888
|
+
}
|
|
7889
|
+
};
|
|
7890
|
+
request.open("GET", ParticleHelper.SnippetUrl + "/" + trimmed.replace(/#/g, "/"), true);
|
|
7891
|
+
request.send();
|
|
7892
|
+
}, [applyParticleSystemJsonToSystem, scene, system]);
|
|
7893
|
+
const saveToSnippetServer = useCallback(() => {
|
|
7894
|
+
// Serialize once and post as snippet payload.
|
|
7895
|
+
const content = JSON.stringify(system.serialize(true));
|
|
7896
|
+
const xmlHttp = new XMLHttpRequest();
|
|
7897
|
+
xmlHttp.onreadystatechange = () => {
|
|
7898
|
+
if (xmlHttp.readyState !== 4) {
|
|
7899
|
+
return;
|
|
7900
|
+
}
|
|
7901
|
+
if (xmlHttp.status !== 200) {
|
|
7902
|
+
alert("Unable to save your particle system");
|
|
7903
|
+
return;
|
|
7904
|
+
}
|
|
7905
|
+
try {
|
|
7906
|
+
const snippet = JSON.parse(xmlHttp.responseText);
|
|
7907
|
+
system.snippetId = snippet.id;
|
|
7908
|
+
if (snippet.version && snippet.version !== "0") {
|
|
7909
|
+
system.snippetId += "#" + snippet.version;
|
|
7910
|
+
}
|
|
7911
|
+
// Copy to clipboard when available.
|
|
7912
|
+
if (navigator.clipboard) {
|
|
7913
|
+
void navigator.clipboard.writeText(system.snippetId);
|
|
7708
7914
|
}
|
|
7709
|
-
system.
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7915
|
+
PersistSnippetId(system.snippetId);
|
|
7916
|
+
alert("Particle system saved with ID: " + system.snippetId + " (the id was also saved to your clipboard)");
|
|
7917
|
+
}
|
|
7918
|
+
catch (e) {
|
|
7919
|
+
alert("Unable to save your particle system: " + e);
|
|
7920
|
+
}
|
|
7921
|
+
};
|
|
7922
|
+
xmlHttp.open("POST", ParticleHelper.SnippetUrl + (system.snippetId ? "/" + system.snippetId : ""), true);
|
|
7923
|
+
xmlHttp.setRequestHeader("Content-Type", "application/json");
|
|
7924
|
+
const dataToSend = {
|
|
7925
|
+
payload: JSON.stringify({
|
|
7926
|
+
particleSystem: content,
|
|
7927
|
+
}),
|
|
7928
|
+
name: "",
|
|
7929
|
+
description: "",
|
|
7930
|
+
tags: "",
|
|
7931
|
+
};
|
|
7932
|
+
xmlHttp.send(JSON.stringify(dataToSend));
|
|
7933
|
+
}, [system]);
|
|
7934
|
+
return (jsxs(Fragment, { children: [jsx(StringifiedPropertyLine, { label: "Capacity", description: "Maximum number of particles in the system.", value: capacity }), jsx(StringifiedPropertyLine, { label: "Active Particles", description: "Current number of active particles.", value: activeCount }), jsx(BoundProperty, { component: NumberDropdownPropertyLine, label: "Blend Mode", target: system, propertyKey: "blendMode", options: BlendModeOptions }), jsx(BoundProperty, { component: Vector3PropertyLine, label: "World Offset", target: system, propertyKey: "worldOffset" }), !system.isNodeGenerated && jsx(BoundProperty, { component: Vector3PropertyLine, label: "Gravity", target: system, propertyKey: "gravity" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Is Billboard", target: system, propertyKey: "isBillboardBased" }), isBillboardBased && (jsx(BoundProperty, { component: NumberDropdownPropertyLine, label: "Billboard Mode", target: system, propertyKey: "billboardMode", options: ParticleBillboardModeOptions })), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Is Local", target: system, propertyKey: "isLocal" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Force Depth Write", target: system, propertyKey: "forceDepthWrite" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Update Speed", target: system, propertyKey: "updateSpeed", min: 0, step: 0.01 }), jsx(ButtonLine, { label: system.isNodeGenerated ? "Edit in Node Particle Editor (coming soon)" : "View in Node Particle Editor (coming soon)", disabled: true, onClick: () => {
|
|
7935
|
+
// Hook up once Node Particle Editor UX is wired.
|
|
7936
|
+
} }), isStopping ? (jsx(TextPropertyLine, { label: "System is stopping...", value: "" })) : isAlive ? (jsx(ButtonLine, { label: "Stop", onClick: () => {
|
|
7937
|
+
setStopRequested(true);
|
|
7938
|
+
system.stop();
|
|
7939
|
+
} })) : (jsx(ButtonLine, { label: "Start", onClick: () => {
|
|
7940
|
+
setStopRequested(false);
|
|
7941
|
+
system.start();
|
|
7942
|
+
} })), !system.isNodeGenerated && (jsxs(Fragment, { children: [jsx(FileUploadLine, { label: "Load from file", accept: ".json", onClick: (files) => {
|
|
7943
|
+
if (files.length === 0) {
|
|
7944
|
+
return;
|
|
7945
|
+
}
|
|
7946
|
+
const file = files[0];
|
|
7947
|
+
Tools.ReadFile(file, (data) => {
|
|
7948
|
+
const jsonObject = ParseJsonLoadContents(data);
|
|
7949
|
+
if (!jsonObject) {
|
|
7950
|
+
alert("Unable to load particle system from file.");
|
|
7951
|
+
return;
|
|
7952
|
+
}
|
|
7953
|
+
applyParticleSystemJsonToSystem(jsonObject);
|
|
7954
|
+
}, undefined, true);
|
|
7955
|
+
} }), jsx(ButtonLine, { label: "Save to file", onClick: () => {
|
|
7956
|
+
// Download serialization as a JSON file.
|
|
7957
|
+
const data = JSON.stringify(system.serialize(true), null, 2);
|
|
7958
|
+
const blob = new Blob([data], { type: "application/json" });
|
|
7959
|
+
const name = (system.name && system.name.trim().length > 0 ? system.name.trim() : "particleSystem") + ".json";
|
|
7960
|
+
Tools.Download(blob, name);
|
|
7961
|
+
} }), snippetId && jsx(TextPropertyLine, { label: "Snippet ID", value: snippetId }), jsx(ButtonLine, { label: "Load from snippet server", onClick: loadFromSnippetServer }), jsx(ButtonLine, { label: "Save to snippet server", onClick: saveToSnippetServer })] }))] }));
|
|
7713
7962
|
};
|
|
7963
|
+
/**
|
|
7964
|
+
* Display attractor-related properties for a particle system.
|
|
7965
|
+
* @param props Component props.
|
|
7966
|
+
* @returns Render property lines.
|
|
7967
|
+
*/
|
|
7714
7968
|
const ParticleSystemAttractorProperties = (props) => {
|
|
7715
7969
|
const { particleSystem: system } = props;
|
|
7716
|
-
const
|
|
7970
|
+
const attractorsGetter = useCallback(() => system.attractors ?? [], [system]);
|
|
7971
|
+
const attractors = useObservableArray(system, attractorsGetter, "addAttractor", "removeAttractor");
|
|
7717
7972
|
const scene = system.getScene();
|
|
7718
7973
|
return (jsx(Fragment, { children: scene ? (jsx(AttractorList, { attractors: attractors, scene: scene, system: system })) : (
|
|
7719
|
-
//
|
|
7974
|
+
// Handle missing scene defensively.
|
|
7720
7975
|
jsx(MessageBar, { intent: "info", title: "No Scene Available", message: "Cannot display attractors without a scene" })) }));
|
|
7721
7976
|
};
|
|
7722
|
-
|
|
7723
|
-
|
|
7977
|
+
/**
|
|
7978
|
+
* Display emitter-related properties for a particle system.
|
|
7979
|
+
* @param props Component props.
|
|
7980
|
+
* @returns Render property lines.
|
|
7981
|
+
*/
|
|
7982
|
+
const ParticleSystemEmitterProperties = (props) => {
|
|
7983
|
+
const { particleSystem: system, selectionService } = props;
|
|
7984
|
+
const scene = system.getScene();
|
|
7985
|
+
const emitter = useProperty(system, "emitter");
|
|
7986
|
+
const emitterObject = emitter && !(emitter instanceof Vector3) ? emitter : undefined;
|
|
7987
|
+
const [sceneNodesVersion, setSceneNodesVersion] = useState(0);
|
|
7988
|
+
useEffect(() => {
|
|
7989
|
+
if (!scene) {
|
|
7990
|
+
return;
|
|
7991
|
+
}
|
|
7992
|
+
// Bump a local version counter whenever nodes change to keep emitter options up-to-date.
|
|
7993
|
+
const bump = () => setSceneNodesVersion((value) => value + 1);
|
|
7994
|
+
const newMeshToken = scene.onNewMeshAddedObservable.add(bump);
|
|
7995
|
+
const meshRemovedToken = scene.onMeshRemovedObservable.add(bump);
|
|
7996
|
+
const newTransformNodeToken = scene.onNewTransformNodeAddedObservable.add(bump);
|
|
7997
|
+
const transformNodeRemovedToken = scene.onTransformNodeRemovedObservable.add(bump);
|
|
7998
|
+
return () => {
|
|
7999
|
+
scene.onNewMeshAddedObservable.remove(newMeshToken);
|
|
8000
|
+
scene.onMeshRemovedObservable.remove(meshRemovedToken);
|
|
8001
|
+
scene.onNewTransformNodeAddedObservable.remove(newTransformNodeToken);
|
|
8002
|
+
scene.onTransformNodeRemovedObservable.remove(transformNodeRemovedToken);
|
|
8003
|
+
};
|
|
8004
|
+
}, [scene]);
|
|
8005
|
+
const sceneNodes = useMemo(() => {
|
|
8006
|
+
if (!scene) {
|
|
8007
|
+
return [];
|
|
8008
|
+
}
|
|
8009
|
+
const seenUniqueIds = new Set();
|
|
8010
|
+
const unique = [];
|
|
8011
|
+
for (const mesh of scene.meshes) {
|
|
8012
|
+
const uniqueId = mesh.uniqueId;
|
|
8013
|
+
if (typeof uniqueId === "number") {
|
|
8014
|
+
if (seenUniqueIds.has(uniqueId)) {
|
|
8015
|
+
continue;
|
|
8016
|
+
}
|
|
8017
|
+
seenUniqueIds.add(uniqueId);
|
|
8018
|
+
}
|
|
8019
|
+
unique.push(mesh);
|
|
8020
|
+
}
|
|
8021
|
+
const emitterUniqueId = emitterObject?.uniqueId;
|
|
8022
|
+
if (emitterObject && emitterUniqueId !== undefined && !seenUniqueIds.has(emitterUniqueId)) {
|
|
8023
|
+
// Keep the current emitter visible even if it isn't present in the scene arrays for any reason.
|
|
8024
|
+
unique.unshift(emitterObject);
|
|
8025
|
+
}
|
|
8026
|
+
return unique;
|
|
8027
|
+
}, [scene, sceneNodesVersion, emitterObject]);
|
|
8028
|
+
const emitterSelectionValue = !emitter ? "none" : emitter instanceof Vector3 ? "position" : `node:${emitter.uniqueId}`;
|
|
8029
|
+
const emitterVector = emitter instanceof Vector3 ? emitter : undefined;
|
|
8030
|
+
// Subscribe to Vector3 internal components to re-render on in-place mutations.
|
|
8031
|
+
useProperty(emitterVector, "_x");
|
|
8032
|
+
useProperty(emitterVector, "_y");
|
|
8033
|
+
useProperty(emitterVector, "_z");
|
|
8034
|
+
const particleEmitterType = useProperty(system, "particleEmitterType");
|
|
8035
|
+
// Derive the current dropdown value from the current instance to stay in sync with external changes.
|
|
8036
|
+
const derivedEmitterTypeKey = (() => {
|
|
8037
|
+
if (particleEmitterType instanceof SphereParticleEmitter) {
|
|
8038
|
+
return "sphere";
|
|
8039
|
+
}
|
|
8040
|
+
if (particleEmitterType instanceof ConeParticleEmitter) {
|
|
8041
|
+
return "cone";
|
|
8042
|
+
}
|
|
8043
|
+
if (particleEmitterType instanceof CylinderParticleEmitter) {
|
|
8044
|
+
return "cylinder";
|
|
8045
|
+
}
|
|
8046
|
+
if (particleEmitterType instanceof HemisphericParticleEmitter) {
|
|
8047
|
+
return "hemispheric";
|
|
8048
|
+
}
|
|
8049
|
+
if (particleEmitterType instanceof PointParticleEmitter) {
|
|
8050
|
+
return "point";
|
|
8051
|
+
}
|
|
8052
|
+
if (particleEmitterType instanceof MeshParticleEmitter) {
|
|
8053
|
+
return "mesh";
|
|
8054
|
+
}
|
|
8055
|
+
// Fall back to "box" for unknown emitter types to keep the dropdown valid.
|
|
8056
|
+
return "box";
|
|
8057
|
+
})();
|
|
8058
|
+
const [emitterTypeKey, setEmitterTypeKey] = useState(derivedEmitterTypeKey);
|
|
8059
|
+
useEffect(() => {
|
|
8060
|
+
// Keep local dropdown state aligned with the derived key when the engine changes underneath.
|
|
8061
|
+
setEmitterTypeKey(derivedEmitterTypeKey);
|
|
8062
|
+
}, [derivedEmitterTypeKey]);
|
|
8063
|
+
return (jsxs(Fragment, { children: [jsx(StringDropdownPropertyLine, { label: "Emitter", value: emitterSelectionValue, options: [
|
|
8064
|
+
{ label: "None", value: "none" },
|
|
8065
|
+
{ label: "Position", value: "position" },
|
|
8066
|
+
...sceneNodes.map((node) => {
|
|
8067
|
+
const uniqueId = node.uniqueId;
|
|
8068
|
+
const name = node.name ?? "(unnamed)";
|
|
8069
|
+
const label = `${name} (#${uniqueId})`;
|
|
8070
|
+
return {
|
|
8071
|
+
label,
|
|
8072
|
+
value: `node:${uniqueId}`,
|
|
8073
|
+
};
|
|
8074
|
+
}),
|
|
8075
|
+
], onChange: (value) => {
|
|
8076
|
+
const next = value;
|
|
8077
|
+
if (next === "none") {
|
|
8078
|
+
system.emitter = null;
|
|
8079
|
+
return;
|
|
8080
|
+
}
|
|
8081
|
+
if (next === "position") {
|
|
8082
|
+
if (!(system.emitter instanceof Vector3)) {
|
|
8083
|
+
system.emitter = Vector3.Zero();
|
|
8084
|
+
}
|
|
8085
|
+
return;
|
|
8086
|
+
}
|
|
8087
|
+
const uniqueIdText = next.replace("node:", "");
|
|
8088
|
+
const uniqueId = Number(uniqueIdText);
|
|
8089
|
+
const node = sceneNodes.find((candidate) => candidate.uniqueId === uniqueId);
|
|
8090
|
+
if (node) {
|
|
8091
|
+
system.emitter = node;
|
|
8092
|
+
}
|
|
8093
|
+
} }), emitterSelectionValue === "position" && emitterVector && (jsx(Vector3PropertyLine, { label: "Position", value: emitterVector, onChange: (value) => {
|
|
8094
|
+
if (system.emitter instanceof Vector3) {
|
|
8095
|
+
system.emitter.copyFrom(value);
|
|
8096
|
+
}
|
|
8097
|
+
else {
|
|
8098
|
+
system.emitter = value;
|
|
8099
|
+
}
|
|
8100
|
+
} })), emitterSelectionValue !== "none" && emitter && !(emitter instanceof Vector3) && (jsx(LinkToEntityPropertyLine, { label: "Entity", entity: emitter, selectionService: selectionService })), !system.isNodeGenerated && (jsx(StringDropdownPropertyLine, { label: "Type", value: emitterTypeKey, options: [
|
|
8101
|
+
{ label: "Box", value: "box" },
|
|
8102
|
+
{ label: "Cone", value: "cone" },
|
|
8103
|
+
{ label: "Cylinder", value: "cylinder" },
|
|
8104
|
+
{ label: "Hemispheric", value: "hemispheric" },
|
|
8105
|
+
{ label: "Point", value: "point" },
|
|
8106
|
+
{ label: "Mesh", value: "mesh" },
|
|
8107
|
+
{ label: "Sphere", value: "sphere" },
|
|
8108
|
+
], onChange: (value) => {
|
|
8109
|
+
const next = value;
|
|
8110
|
+
setEmitterTypeKey(next);
|
|
8111
|
+
// Update the engine by swapping the particleEmitterType instance to match the selected key.
|
|
8112
|
+
switch (next) {
|
|
8113
|
+
case "box":
|
|
8114
|
+
system.createBoxEmitter(new Vector3(0, 1, 0), new Vector3(0, 1, 0), new Vector3(-0.5, -0.5, -0.5), new Vector3(0.5, 0.5, 0.5));
|
|
8115
|
+
break;
|
|
8116
|
+
case "sphere":
|
|
8117
|
+
system.createSphereEmitter(1, 1);
|
|
8118
|
+
break;
|
|
8119
|
+
case "cone":
|
|
8120
|
+
system.createConeEmitter(1, Math.PI / 4);
|
|
8121
|
+
break;
|
|
8122
|
+
case "cylinder":
|
|
8123
|
+
system.createCylinderEmitter(1, 1, 1, 0);
|
|
8124
|
+
break;
|
|
8125
|
+
case "hemispheric":
|
|
8126
|
+
system.createHemisphericEmitter(1, 1);
|
|
8127
|
+
break;
|
|
8128
|
+
case "point":
|
|
8129
|
+
system.createPointEmitter(new Vector3(0, 1, 0), new Vector3(0, 1, 0));
|
|
8130
|
+
break;
|
|
8131
|
+
case "mesh": {
|
|
8132
|
+
// Default to the first mesh in the scene when available, then allow changes via "Source".
|
|
8133
|
+
const defaultMesh = scene?.meshes?.[0] ?? null;
|
|
8134
|
+
system.particleEmitterType = new MeshParticleEmitter(defaultMesh);
|
|
8135
|
+
break;
|
|
8136
|
+
}
|
|
8137
|
+
}
|
|
8138
|
+
} })), !system.isNodeGenerated && particleEmitterType instanceof MeshParticleEmitter && (jsx(Fragment, { children: scene && scene.meshes.length > 0 ? (jsx(StringDropdownPropertyLine, { label: "Source", value: particleEmitterType.mesh ? `mesh:${particleEmitterType.mesh.uniqueId}` : `mesh:${scene.meshes[0].uniqueId}`, options: scene.meshes.map((mesh) => {
|
|
8139
|
+
const uniqueId = mesh.uniqueId;
|
|
8140
|
+
const name = mesh.name ?? "(unnamed)";
|
|
8141
|
+
const label = `${name} (#${uniqueId})`;
|
|
8142
|
+
return {
|
|
8143
|
+
label,
|
|
8144
|
+
value: `mesh:${uniqueId}`,
|
|
8145
|
+
};
|
|
8146
|
+
}), onChange: (value) => {
|
|
8147
|
+
const next = String(value);
|
|
8148
|
+
const uniqueIdText = next.replace("mesh:", "");
|
|
8149
|
+
const uniqueId = Number(uniqueIdText);
|
|
8150
|
+
const mesh = scene.meshes.find((candidate) => candidate.uniqueId === uniqueId) ?? null;
|
|
8151
|
+
particleEmitterType.mesh = mesh;
|
|
8152
|
+
} })) : (jsx(TextPropertyLine, { label: "Source", value: "No meshes in scene." })) })), !system.isNodeGenerated && particleEmitterType instanceof BoxParticleEmitter && (jsxs(Fragment, { children: [jsx(BoundProperty, { component: Vector3PropertyLine, label: "Direction1", target: particleEmitterType, propertyKey: "direction1" }), jsx(BoundProperty, { component: Vector3PropertyLine, label: "Direction2", target: particleEmitterType, propertyKey: "direction2" }), jsx(BoundProperty, { component: Vector3PropertyLine, label: "Min emit box", target: particleEmitterType, propertyKey: "minEmitBox" }), jsx(BoundProperty, { component: Vector3PropertyLine, label: "Max emit box", target: particleEmitterType, propertyKey: "maxEmitBox" })] })), !system.isNodeGenerated && particleEmitterType instanceof ConeParticleEmitter && (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Radius range", target: particleEmitterType, propertyKey: "radiusRange", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Height range", target: particleEmitterType, propertyKey: "heightRange", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Emit from spawn point only", target: particleEmitterType, propertyKey: "emitFromSpawnPointOnly" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Direction randomizer", target: particleEmitterType, propertyKey: "directionRandomizer", min: 0, max: 1, step: 0.01 })] })), !system.isNodeGenerated && particleEmitterType instanceof SphereParticleEmitter && (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Radius", target: particleEmitterType, propertyKey: "radius", min: 0, step: 0.1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Radius range", target: particleEmitterType, propertyKey: "radiusRange", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Direction randomizer", target: particleEmitterType, propertyKey: "directionRandomizer", min: 0, max: 1, step: 0.01 })] })), !system.isNodeGenerated && particleEmitterType instanceof CylinderParticleEmitter && (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Radius", target: particleEmitterType, propertyKey: "radius", min: 0, step: 0.1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Height", target: particleEmitterType, propertyKey: "height", min: 0, step: 0.1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Radius range", target: particleEmitterType, propertyKey: "radiusRange", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Direction randomizer", target: particleEmitterType, propertyKey: "directionRandomizer", min: 0, max: 1, step: 0.01 })] })), !system.isNodeGenerated && particleEmitterType instanceof HemisphericParticleEmitter && (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Radius", target: particleEmitterType, propertyKey: "radius", min: 0, step: 0.1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Radius range", target: particleEmitterType, propertyKey: "radiusRange", min: 0, max: 1, step: 0.01 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Direction randomizer", target: particleEmitterType, propertyKey: "directionRandomizer", min: 0, max: 1, step: 0.01 })] })), !system.isNodeGenerated && particleEmitterType instanceof PointParticleEmitter && (jsxs(Fragment, { children: [jsx(BoundProperty, { component: Vector3PropertyLine, label: "Direction1", target: particleEmitterType, propertyKey: "direction1" }), jsx(BoundProperty, { component: Vector3PropertyLine, label: "Direction2", target: particleEmitterType, propertyKey: "direction2" })] })), !system.isNodeGenerated && !scene && jsx(TextPropertyLine, { label: "Emitter", value: "No scene available." })] }));
|
|
8153
|
+
};
|
|
8154
|
+
/**
|
|
8155
|
+
* Display emission-related properties for a particle system.
|
|
8156
|
+
* @param props Component props.
|
|
8157
|
+
* @returns Render property lines.
|
|
8158
|
+
*/
|
|
8159
|
+
const ParticleSystemEmissionProperties = (props) => {
|
|
8160
|
+
const { particleSystem: system } = props;
|
|
8161
|
+
const emitRateGradientsGetter = useCallback(() => system.getEmitRateGradients(), [system]);
|
|
8162
|
+
const emitRateGradients = useObservableArray(system, emitRateGradientsGetter, "addEmitRateGradient", "removeEmitRateGradient", "forceRefreshGradients");
|
|
8163
|
+
const velocityGradientsGetter = useCallback(() => system.getVelocityGradients(), [system]);
|
|
8164
|
+
const velocityGradients = useObservableArray(system, velocityGradientsGetter, "addVelocityGradient", "removeVelocityGradient", "forceRefreshGradients");
|
|
8165
|
+
const limitVelocityGradientsGetter = useCallback(() => system.getLimitVelocityGradients(), [system]);
|
|
8166
|
+
const limitVelocityGradients = useObservableArray(system, limitVelocityGradientsGetter, "addLimitVelocityGradient", "removeLimitVelocityGradient", "forceRefreshGradients");
|
|
8167
|
+
const dragGradientsGetter = useCallback(() => system.getDragGradients(), [system]);
|
|
8168
|
+
const dragGradients = useObservableArray(system, dragGradientsGetter, "addDragGradient", "removeDragGradient", "forceRefreshGradients");
|
|
8169
|
+
const useEmitRateGradients = (emitRateGradients?.length ?? 0) > 0;
|
|
8170
|
+
const useVelocityGradients = (velocityGradients?.length ?? 0) > 0;
|
|
8171
|
+
const useLimitVelocityGradients = (limitVelocityGradients?.length ?? 0) > 0;
|
|
8172
|
+
const useDragGradients = (dragGradients?.length ?? 0) > 0;
|
|
8173
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Emit rate", target: system, propertyKey: "emitRate", min: 0, step: 1 }), !system.isNodeGenerated && !useEmitRateGradients && (jsx(ButtonLine, { label: "Use Emit rate gradients", onClick: () => {
|
|
8174
|
+
system.addEmitRateGradient(0, system.emitRate, system.emitRate);
|
|
8175
|
+
system.forceRefreshGradients();
|
|
8176
|
+
} })), !system.isNodeGenerated && useEmitRateGradients && (jsx(FactorGradientList, { gradients: emitRateGradients, label: "Emit Rate Gradient", removeGradient: (gradient) => {
|
|
8177
|
+
system.removeEmitRateGradient(gradient.gradient);
|
|
8178
|
+
system.forceRefreshGradients();
|
|
8179
|
+
}, addGradient: (gradient) => {
|
|
8180
|
+
if (gradient) {
|
|
8181
|
+
system.addEmitRateGradient(gradient.gradient, gradient.factor1, gradient.factor2);
|
|
8182
|
+
}
|
|
8183
|
+
else {
|
|
8184
|
+
system.addEmitRateGradient(0, system.emitRate, system.emitRate);
|
|
8185
|
+
}
|
|
8186
|
+
system.forceRefreshGradients();
|
|
8187
|
+
}, onChange: (_gradient) => {
|
|
8188
|
+
system.forceRefreshGradients();
|
|
8189
|
+
} })), !system.isNodeGenerated && (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Min Emit Power", target: system, propertyKey: "minEmitPower", min: 0, step: 0.1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Max Emit Power", target: system, propertyKey: "maxEmitPower", min: 0, step: 0.1 })] })), !system.isNodeGenerated && !useVelocityGradients && (jsx(ButtonLine, { label: "Use Velocity gradients", onClick: () => {
|
|
8190
|
+
system.addVelocityGradient(0, 1, 1);
|
|
8191
|
+
system.forceRefreshGradients();
|
|
8192
|
+
} })), !system.isNodeGenerated && useVelocityGradients && (jsx(FactorGradientList, { gradients: velocityGradients, label: "Velocity Gradient", removeGradient: (gradient) => {
|
|
8193
|
+
system.removeVelocityGradient(gradient.gradient);
|
|
8194
|
+
system.forceRefreshGradients();
|
|
8195
|
+
}, addGradient: (gradient) => {
|
|
8196
|
+
if (gradient) {
|
|
8197
|
+
system.addVelocityGradient(gradient.gradient, gradient.factor1, gradient.factor2);
|
|
8198
|
+
}
|
|
8199
|
+
else {
|
|
8200
|
+
system.addVelocityGradient(0, 1, 1);
|
|
8201
|
+
}
|
|
8202
|
+
system.forceRefreshGradients();
|
|
8203
|
+
}, onChange: (_gradient) => {
|
|
8204
|
+
system.forceRefreshGradients();
|
|
8205
|
+
} })), !system.isNodeGenerated && !useLimitVelocityGradients && (jsx(ButtonLine, { label: "Use Limit Velocity gradients", onClick: () => {
|
|
8206
|
+
system.addLimitVelocityGradient(0, 1, 1);
|
|
8207
|
+
system.forceRefreshGradients();
|
|
8208
|
+
} })), !system.isNodeGenerated && useLimitVelocityGradients && (jsx(FactorGradientList, { gradients: limitVelocityGradients, label: "Limit Velocity Gradient", removeGradient: (gradient) => {
|
|
8209
|
+
system.removeLimitVelocityGradient(gradient.gradient);
|
|
8210
|
+
system.forceRefreshGradients();
|
|
8211
|
+
}, addGradient: (gradient) => {
|
|
8212
|
+
if (gradient) {
|
|
8213
|
+
system.addLimitVelocityGradient(gradient.gradient, gradient.factor1, gradient.factor2);
|
|
8214
|
+
}
|
|
8215
|
+
else {
|
|
8216
|
+
system.addLimitVelocityGradient(0, 1, 1);
|
|
8217
|
+
}
|
|
8218
|
+
system.forceRefreshGradients();
|
|
8219
|
+
}, onChange: (_gradient) => {
|
|
8220
|
+
system.forceRefreshGradients();
|
|
8221
|
+
} })), !system.isNodeGenerated && !useDragGradients && (jsx(ButtonLine, { label: "Use Drag gradients", onClick: () => {
|
|
8222
|
+
system.addDragGradient(0, 1, 1);
|
|
8223
|
+
system.forceRefreshGradients();
|
|
8224
|
+
} })), !system.isNodeGenerated && useDragGradients && (jsx(FactorGradientList, { gradients: dragGradients, label: "Drag Gradient", removeGradient: (gradient) => {
|
|
8225
|
+
system.removeDragGradient(gradient.gradient);
|
|
8226
|
+
system.forceRefreshGradients();
|
|
8227
|
+
}, addGradient: (gradient) => {
|
|
8228
|
+
if (gradient) {
|
|
8229
|
+
system.addDragGradient(gradient.gradient, gradient.factor1, gradient.factor2);
|
|
8230
|
+
}
|
|
8231
|
+
else {
|
|
8232
|
+
system.addDragGradient(0, 1, 1);
|
|
8233
|
+
}
|
|
8234
|
+
system.forceRefreshGradients();
|
|
8235
|
+
}, onChange: (_gradient) => {
|
|
8236
|
+
system.forceRefreshGradients();
|
|
8237
|
+
} }))] }));
|
|
8238
|
+
};
|
|
8239
|
+
/**
|
|
8240
|
+
* Display size-related properties for a particle system.
|
|
8241
|
+
* @param props Component props.
|
|
8242
|
+
* @returns Render property lines.
|
|
8243
|
+
*/
|
|
8244
|
+
const ParticleSystemSizeProperties = (props) => {
|
|
8245
|
+
const { particleSystem: system } = props;
|
|
8246
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Min size", target: system, propertyKey: "minSize", min: 0, step: 0.1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Max size", target: system, propertyKey: "maxSize", min: 0, step: 0.1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Min scale x", target: system, propertyKey: "minScaleX", min: 0, step: 0.1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Max scale x", target: system, propertyKey: "maxScaleX", min: 0, step: 0.1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Min scale y", target: system, propertyKey: "minScaleY", min: 0, step: 0.1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Max scale y", target: system, propertyKey: "maxScaleY", min: 0, step: 0.1 })] }));
|
|
8247
|
+
};
|
|
8248
|
+
/**
|
|
8249
|
+
* Display lifetime-related properties for a particle system.
|
|
8250
|
+
* @param props Component props.
|
|
8251
|
+
* @returns Render property lines.
|
|
8252
|
+
*/
|
|
8253
|
+
const ParticleSystemLifetimeProperties = (props) => {
|
|
8254
|
+
const { particleSystem: system } = props;
|
|
8255
|
+
if (system.isNodeGenerated) {
|
|
8256
|
+
return jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Target stop duration", target: system, propertyKey: "targetStopDuration", min: 0, step: 0.1 });
|
|
8257
|
+
}
|
|
8258
|
+
const lifeTimeGradientsGetter = useCallback(() => system.getLifeTimeGradients(), [system]);
|
|
8259
|
+
const lifeTimeGradients = useObservableArray(system, lifeTimeGradientsGetter, "addLifeTimeGradient", "removeLifeTimeGradient", "forceRefreshGradients");
|
|
8260
|
+
const useLifeTimeGradients = (lifeTimeGradients?.length ?? 0) > 0;
|
|
8261
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Min lifetime", target: system, propertyKey: "minLifeTime", min: 0, step: 0.1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Max lifetime", target: system, propertyKey: "maxLifeTime", min: 0, step: 0.1 }), !useLifeTimeGradients && (jsx(ButtonLine, { label: "Use Lifetime gradients", onClick: () => {
|
|
8262
|
+
system.addLifeTimeGradient(0, system.minLifeTime, system.maxLifeTime);
|
|
8263
|
+
system.forceRefreshGradients();
|
|
8264
|
+
} })), useLifeTimeGradients && (jsx(FactorGradientList, { gradients: lifeTimeGradients, label: "Lifetime Gradient", removeGradient: (gradient) => {
|
|
8265
|
+
system.removeLifeTimeGradient(gradient.gradient);
|
|
8266
|
+
system.forceRefreshGradients();
|
|
8267
|
+
}, addGradient: (gradient) => {
|
|
8268
|
+
if (gradient) {
|
|
8269
|
+
system.addLifeTimeGradient(gradient.gradient, gradient.factor1, gradient.factor2);
|
|
8270
|
+
}
|
|
8271
|
+
else {
|
|
8272
|
+
system.addLifeTimeGradient(0, system.minLifeTime, system.maxLifeTime);
|
|
8273
|
+
}
|
|
8274
|
+
system.forceRefreshGradients();
|
|
8275
|
+
}, onChange: (_gradient) => {
|
|
8276
|
+
system.forceRefreshGradients();
|
|
8277
|
+
} })), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Target stop duration", target: system, propertyKey: "targetStopDuration", min: 0, step: 0.1 })] }));
|
|
8278
|
+
};
|
|
8279
|
+
/**
|
|
8280
|
+
* Display color-related properties for a particle system.
|
|
8281
|
+
* @param props Component props.
|
|
8282
|
+
* @returns Render property lines.
|
|
8283
|
+
*/
|
|
8284
|
+
const ParticleSystemColorProperties = (props) => {
|
|
8285
|
+
const { particleSystem: system } = props;
|
|
8286
|
+
const colorGradientsGetter = useCallback(() => system.getColorGradients(), [system]);
|
|
8287
|
+
const colorGradients = useObservableArray(system, colorGradientsGetter, "addColorGradient", "removeColorGradient", "forceRefreshGradients");
|
|
8288
|
+
const useRampGradients = useProperty(system, "useRampGradients");
|
|
8289
|
+
const rampGradientsGetter = useCallback(() => system.getRampGradients(), [system]);
|
|
8290
|
+
const rampGradients = useObservableArray(system, rampGradientsGetter, "addRampGradient", "removeRampGradient", "forceRefreshGradients");
|
|
8291
|
+
const colorRemapGradientsGetter = useCallback(() => system.getColorRemapGradients(), [system]);
|
|
8292
|
+
const colorRemapGradients = useObservableArray(system, colorRemapGradientsGetter, "addColorRemapGradient", "removeColorRemapGradient", "forceRefreshGradients");
|
|
8293
|
+
const alphaRemapGradientsGetter = useCallback(() => system.getAlphaRemapGradients(), [system]);
|
|
8294
|
+
const alphaRemapGradients = useObservableArray(system, alphaRemapGradientsGetter, "addAlphaRemapGradient", "removeAlphaRemapGradient", "forceRefreshGradients");
|
|
8295
|
+
const hasColorGradients = (colorGradients?.length ?? 0) > 0;
|
|
8296
|
+
const hasRampGradients = (rampGradients?.length ?? 0) > 0;
|
|
8297
|
+
const hasColorRemapGradients = (colorRemapGradients?.length ?? 0) > 0;
|
|
8298
|
+
const hasAlphaRemapGradients = (alphaRemapGradients?.length ?? 0) > 0;
|
|
8299
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: Color4PropertyLine, label: "Color 1", target: system, propertyKey: "color1" }), jsx(BoundProperty, { component: Color4PropertyLine, label: "Color 2", target: system, propertyKey: "color2" }), jsx(BoundProperty, { component: Color4PropertyLine, label: "Color dead", target: system, propertyKey: "colorDead" }), !hasColorGradients && (jsx(ButtonLine, { label: "Use Color gradients", onClick: () => {
|
|
8300
|
+
system.addColorGradient(0, system.color1, system.color1);
|
|
8301
|
+
system.addColorGradient(1, system.color2, system.color2);
|
|
8302
|
+
system.forceRefreshGradients();
|
|
8303
|
+
} })), hasColorGradients && (jsx(Color4GradientList, { gradients: colorGradients, label: "Color Gradient", removeGradient: (gradient) => {
|
|
8304
|
+
system.removeColorGradient(gradient.gradient);
|
|
8305
|
+
system.forceRefreshGradients();
|
|
8306
|
+
}, addGradient: (gradient) => {
|
|
8307
|
+
if (gradient) {
|
|
8308
|
+
system.addColorGradient(gradient.gradient, gradient.color1, gradient.color2);
|
|
8309
|
+
}
|
|
8310
|
+
else {
|
|
8311
|
+
system.addColorGradient(0, system.color1, system.color1);
|
|
8312
|
+
system.addColorGradient(1, system.color2, system.color2);
|
|
8313
|
+
}
|
|
8314
|
+
system.forceRefreshGradients();
|
|
8315
|
+
}, onChange: (_gradient) => {
|
|
8316
|
+
system.forceRefreshGradients();
|
|
8317
|
+
} })), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Enable Ramp gradients", target: system, propertyKey: "useRampGradients" }), useRampGradients && (jsxs(Fragment, { children: [!hasRampGradients && (jsx(ButtonLine, { label: "Use Ramp gradients", onClick: () => {
|
|
8318
|
+
system.addRampGradient(0, Color3.Black());
|
|
8319
|
+
system.addRampGradient(1, Color3.White());
|
|
8320
|
+
system.forceRefreshGradients();
|
|
8321
|
+
} })), hasRampGradients && (jsx(Color3GradientList, { gradients: rampGradients, label: "Ramp Gradient", removeGradient: (gradient) => {
|
|
8322
|
+
system.removeRampGradient(gradient.gradient);
|
|
8323
|
+
system.forceRefreshGradients();
|
|
8324
|
+
}, addGradient: (gradient) => {
|
|
8325
|
+
if (gradient) {
|
|
8326
|
+
system.addRampGradient(gradient.gradient, gradient.color);
|
|
8327
|
+
}
|
|
8328
|
+
else {
|
|
8329
|
+
system.addRampGradient(0, Color3.Black());
|
|
8330
|
+
system.addRampGradient(1, Color3.White());
|
|
8331
|
+
}
|
|
8332
|
+
system.forceRefreshGradients();
|
|
8333
|
+
}, onChange: () => {
|
|
8334
|
+
system.forceRefreshGradients();
|
|
8335
|
+
} })), !hasColorRemapGradients && (jsx(ButtonLine, { label: "Use Color remap gradients", onClick: () => {
|
|
8336
|
+
system.addColorRemapGradient(0, 0, 1);
|
|
8337
|
+
system.addColorRemapGradient(1, 0, 1);
|
|
8338
|
+
system.forceRefreshGradients();
|
|
8339
|
+
} })), hasColorRemapGradients && (jsx(FactorGradientList, { gradients: colorRemapGradients, label: "Color Remap Gradient", removeGradient: (gradient) => {
|
|
8340
|
+
system.removeColorRemapGradient(gradient.gradient);
|
|
8341
|
+
system.forceRefreshGradients();
|
|
8342
|
+
}, addGradient: (gradient) => {
|
|
8343
|
+
if (gradient) {
|
|
8344
|
+
system.addColorRemapGradient(gradient.gradient, gradient.factor1 ?? 0, gradient.factor2 ?? 1);
|
|
8345
|
+
}
|
|
8346
|
+
else {
|
|
8347
|
+
system.addColorRemapGradient(0, 0, 1);
|
|
8348
|
+
system.addColorRemapGradient(1, 0, 1);
|
|
8349
|
+
}
|
|
8350
|
+
system.forceRefreshGradients();
|
|
8351
|
+
}, onChange: (_gradient) => {
|
|
8352
|
+
system.forceRefreshGradients();
|
|
8353
|
+
} })), !hasAlphaRemapGradients && (jsx(ButtonLine, { label: "Use Alpha remap gradients", onClick: () => {
|
|
8354
|
+
system.addAlphaRemapGradient(0, 0, 1);
|
|
8355
|
+
system.addAlphaRemapGradient(1, 0, 1);
|
|
8356
|
+
system.forceRefreshGradients();
|
|
8357
|
+
} })), hasAlphaRemapGradients && (jsx(FactorGradientList, { gradients: alphaRemapGradients, label: "Alpha Remap Gradient", removeGradient: (gradient) => {
|
|
8358
|
+
system.removeAlphaRemapGradient(gradient.gradient);
|
|
8359
|
+
system.forceRefreshGradients();
|
|
8360
|
+
}, addGradient: (gradient) => {
|
|
8361
|
+
if (gradient) {
|
|
8362
|
+
system.addAlphaRemapGradient(gradient.gradient, gradient.factor1 ?? 0, gradient.factor2 ?? 1);
|
|
8363
|
+
}
|
|
8364
|
+
else {
|
|
8365
|
+
system.addAlphaRemapGradient(0, 0, 1);
|
|
8366
|
+
system.addAlphaRemapGradient(1, 0, 1);
|
|
8367
|
+
}
|
|
8368
|
+
system.forceRefreshGradients();
|
|
8369
|
+
}, onChange: (_gradient) => {
|
|
8370
|
+
system.forceRefreshGradients();
|
|
8371
|
+
} }))] }))] }));
|
|
8372
|
+
};
|
|
8373
|
+
/**
|
|
8374
|
+
* Display rotation-related properties for a particle system.
|
|
8375
|
+
* @param props Component props.
|
|
8376
|
+
* @returns Render property lines.
|
|
8377
|
+
*/
|
|
8378
|
+
const ParticleSystemRotationProperties = (props) => {
|
|
8379
|
+
const { particleSystem: system } = props;
|
|
8380
|
+
const angularSpeedGradientsGetter = useCallback(() => system.getAngularSpeedGradients(), [system]);
|
|
8381
|
+
const angularSpeedGradients = useObservableArray(system, angularSpeedGradientsGetter, "addAngularSpeedGradient", "removeAngularSpeedGradient", "forceRefreshGradients");
|
|
8382
|
+
const useAngularSpeedGradients = (angularSpeedGradients?.length ?? 0) > 0;
|
|
8383
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Min Angular speed", target: system, propertyKey: "minAngularSpeed", step: 0.01 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Max Angular speed", target: system, propertyKey: "maxAngularSpeed", step: 0.01 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Min initial rotation", target: system, propertyKey: "minInitialRotation", step: 0.01 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Max initial rotation", target: system, propertyKey: "maxInitialRotation", step: 0.01 }), !useAngularSpeedGradients && (jsx(ButtonLine, { label: "Use Angular speed gradients", onClick: () => {
|
|
8384
|
+
system.addAngularSpeedGradient(0, system.minAngularSpeed, system.maxAngularSpeed);
|
|
8385
|
+
system.forceRefreshGradients();
|
|
8386
|
+
} })), useAngularSpeedGradients && (jsx(FactorGradientList, { gradients: angularSpeedGradients, label: "Angular Speed Gradient", removeGradient: (gradient) => {
|
|
8387
|
+
system.removeAngularSpeedGradient(gradient.gradient);
|
|
8388
|
+
system.forceRefreshGradients();
|
|
8389
|
+
}, addGradient: (gradient) => {
|
|
8390
|
+
if (gradient) {
|
|
8391
|
+
system.addAngularSpeedGradient(gradient.gradient, gradient.factor1 ?? 0, gradient.factor2);
|
|
8392
|
+
}
|
|
8393
|
+
else {
|
|
8394
|
+
system.addAngularSpeedGradient(0, system.minAngularSpeed, system.maxAngularSpeed);
|
|
8395
|
+
}
|
|
8396
|
+
system.forceRefreshGradients();
|
|
8397
|
+
}, onChange: (_gradient) => {
|
|
8398
|
+
system.forceRefreshGradients();
|
|
8399
|
+
} }))] }));
|
|
8400
|
+
};
|
|
8401
|
+
/**
|
|
8402
|
+
* Display spritesheet-related properties for a particle system.
|
|
8403
|
+
* @param props Component props.
|
|
8404
|
+
* @returns Render property lines.
|
|
8405
|
+
*/
|
|
8406
|
+
const ParticleSystemSpritesheetProperties = (props) => {
|
|
8407
|
+
const { particleSystem: system } = props;
|
|
8408
|
+
return (jsxs(Fragment, { children: [jsx(BoundProperty, { component: SwitchPropertyLine, label: "Animation sheet enabled", target: system, propertyKey: "isAnimationSheetEnabled" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "First sprite index", target: system, propertyKey: "startSpriteCellID", min: 0, step: 1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Last sprite index", target: system, propertyKey: "endSpriteCellID", min: 0, step: 1 }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Animation loop", target: system, propertyKey: "spriteCellLoop" }), jsx(BoundProperty, { component: SwitchPropertyLine, label: "Random cell start index", target: system, propertyKey: "spriteRandomStartCell" }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Cell width", target: system, propertyKey: "spriteCellWidth", min: 0, step: 1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Cell height", target: system, propertyKey: "spriteCellHeight", min: 0, step: 1 }), jsx(BoundProperty, { component: NumberInputPropertyLine, label: "Cell change speed", target: system, propertyKey: "spriteCellChangeSpeed", min: 0, step: 0.01 })] }));
|
|
8409
|
+
};
|
|
8410
|
+
// Return a copied array and re-render when array mutators run.
|
|
8411
|
+
// Intercept add/remove/change functions because the underlying APIs update internal arrays in-place.
|
|
8412
|
+
const useObservableArray = (target, getItems, addFn, removeFn, changeFn) => {
|
|
7724
8413
|
return useObservableState(useCallback(() => {
|
|
7725
|
-
const value =
|
|
8414
|
+
const value = getItems();
|
|
7726
8415
|
return [...(value ?? [])];
|
|
7727
|
-
}, [
|
|
8416
|
+
}, [getItems]), useInterceptObservable("function", target, addFn), useInterceptObservable("function", target, removeFn), changeFn ? useInterceptObservable("function", target, changeFn) : undefined);
|
|
7728
8417
|
};
|
|
7729
8418
|
|
|
8419
|
+
function IsParticleSystem(entity) {
|
|
8420
|
+
return entity instanceof ParticleSystem;
|
|
8421
|
+
}
|
|
8422
|
+
function IsNonNodeParticleSystem(entity) {
|
|
8423
|
+
return entity instanceof ParticleSystem && !entity.isNodeGenerated;
|
|
8424
|
+
}
|
|
8425
|
+
// TODO: This file and particleSystemProperties.tsx still need to handle CPU vs GPU systems differently where applicable.
|
|
7730
8426
|
const ParticleSystemPropertiesServiceDefinition = {
|
|
7731
8427
|
friendlyName: "Particle System Properties",
|
|
7732
|
-
consumes: [PropertiesServiceIdentity],
|
|
7733
|
-
factory: (propertiesService) => {
|
|
7734
|
-
//
|
|
7735
|
-
|
|
7736
|
-
|
|
7737
|
-
|
|
8428
|
+
consumes: [PropertiesServiceIdentity, SelectionServiceIdentity],
|
|
8429
|
+
factory: (propertiesService, selectionService) => {
|
|
8430
|
+
// Register each section in its own call to keep ordering predictable across registrations.
|
|
8431
|
+
// Note: section `order` is not globally sorted across different registrations, so call order matters.
|
|
8432
|
+
const particleSystemGeneralContent = propertiesService.addSectionContent({
|
|
8433
|
+
key: "Particle System General Properties",
|
|
8434
|
+
predicate: IsParticleSystem,
|
|
8435
|
+
content: [
|
|
8436
|
+
{
|
|
8437
|
+
section: "General",
|
|
8438
|
+
order: 1,
|
|
8439
|
+
component: ({ context }) => jsx(ParticleSystemGeneralProperties, { particleSystem: context }),
|
|
8440
|
+
},
|
|
8441
|
+
],
|
|
8442
|
+
});
|
|
8443
|
+
// The Attractors section must not be visible at all (including the accordion entry) for node-generated systems.
|
|
8444
|
+
const particleSystemAttractorsContent = propertiesService.addSectionContent({
|
|
8445
|
+
key: "Particle System Attractors Properties",
|
|
8446
|
+
predicate: IsNonNodeParticleSystem,
|
|
8447
|
+
content: [
|
|
8448
|
+
{
|
|
8449
|
+
section: "Attractors",
|
|
8450
|
+
order: 2,
|
|
8451
|
+
component: ({ context }) => jsx(ParticleSystemAttractorProperties, { particleSystem: context }),
|
|
8452
|
+
},
|
|
8453
|
+
],
|
|
8454
|
+
});
|
|
8455
|
+
const particleSystemEmitterContent = propertiesService.addSectionContent({
|
|
8456
|
+
key: "Particle System Emitter Properties",
|
|
8457
|
+
predicate: IsParticleSystem,
|
|
8458
|
+
content: [
|
|
8459
|
+
{
|
|
8460
|
+
section: "Emitter",
|
|
8461
|
+
order: 3,
|
|
8462
|
+
component: ({ context }) => jsx(ParticleSystemEmitterProperties, { particleSystem: context, selectionService: selectionService }),
|
|
8463
|
+
},
|
|
8464
|
+
],
|
|
8465
|
+
});
|
|
8466
|
+
const particleSystemEmissionContent = propertiesService.addSectionContent({
|
|
8467
|
+
key: "Particle System Emission Properties",
|
|
8468
|
+
predicate: IsParticleSystem,
|
|
7738
8469
|
content: [
|
|
7739
8470
|
{
|
|
7740
8471
|
section: "Emission",
|
|
8472
|
+
order: 4,
|
|
7741
8473
|
component: ({ context }) => jsx(ParticleSystemEmissionProperties, { particleSystem: context }),
|
|
7742
8474
|
},
|
|
8475
|
+
],
|
|
8476
|
+
});
|
|
8477
|
+
// The Size section must not be visible at all (including the accordion entry) for node-generated systems.
|
|
8478
|
+
const particleSystemSizeContent = propertiesService.addSectionContent({
|
|
8479
|
+
key: "Particle System Size Properties",
|
|
8480
|
+
predicate: IsNonNodeParticleSystem,
|
|
8481
|
+
content: [
|
|
7743
8482
|
{
|
|
7744
|
-
section: "
|
|
8483
|
+
section: "Size",
|
|
8484
|
+
order: 5,
|
|
8485
|
+
component: ({ context }) => jsx(ParticleSystemSizeProperties, { particleSystem: context }),
|
|
8486
|
+
},
|
|
8487
|
+
],
|
|
8488
|
+
});
|
|
8489
|
+
// Lifetime is registered for all systems; the component limits the visible fields for node-generated systems.
|
|
8490
|
+
const particleSystemLifetimeContent = propertiesService.addSectionContent({
|
|
8491
|
+
key: "Particle System Lifetime Properties",
|
|
8492
|
+
predicate: IsParticleSystem,
|
|
8493
|
+
content: [
|
|
8494
|
+
{
|
|
8495
|
+
section: "Lifetime",
|
|
8496
|
+
order: 6,
|
|
8497
|
+
component: ({ context }) => jsx(ParticleSystemLifetimeProperties, { particleSystem: context }),
|
|
8498
|
+
},
|
|
8499
|
+
],
|
|
8500
|
+
});
|
|
8501
|
+
// Register Color after Lifetime.
|
|
8502
|
+
const particleSystemColorContent = propertiesService.addSectionContent({
|
|
8503
|
+
key: "Particle System Color Properties",
|
|
8504
|
+
predicate: IsNonNodeParticleSystem,
|
|
8505
|
+
content: [
|
|
8506
|
+
{
|
|
8507
|
+
section: "Colors",
|
|
8508
|
+
order: 7,
|
|
7745
8509
|
component: ({ context }) => jsx(ParticleSystemColorProperties, { particleSystem: context }),
|
|
7746
8510
|
},
|
|
8511
|
+
],
|
|
8512
|
+
});
|
|
8513
|
+
// Register Rotation after Colors.
|
|
8514
|
+
const particleSystemRotationContent = propertiesService.addSectionContent({
|
|
8515
|
+
key: "Particle System Rotation Properties",
|
|
8516
|
+
predicate: IsNonNodeParticleSystem,
|
|
8517
|
+
content: [
|
|
7747
8518
|
{
|
|
7748
|
-
section: "
|
|
7749
|
-
|
|
8519
|
+
section: "Rotation",
|
|
8520
|
+
order: 8,
|
|
8521
|
+
component: ({ context }) => jsx(ParticleSystemRotationProperties, { particleSystem: context }),
|
|
8522
|
+
},
|
|
8523
|
+
],
|
|
8524
|
+
});
|
|
8525
|
+
// Register Spritesheet after Rotation.
|
|
8526
|
+
const particleSystemSpritesheetContent = propertiesService.addSectionContent({
|
|
8527
|
+
key: "Particle System Spritesheet Properties",
|
|
8528
|
+
predicate: IsNonNodeParticleSystem,
|
|
8529
|
+
content: [
|
|
8530
|
+
{
|
|
8531
|
+
section: "Spritesheet",
|
|
8532
|
+
order: 9,
|
|
8533
|
+
component: ({ context }) => jsx(ParticleSystemSpritesheetProperties, { particleSystem: context }),
|
|
7750
8534
|
},
|
|
7751
8535
|
],
|
|
7752
8536
|
});
|
|
7753
8537
|
return {
|
|
7754
8538
|
dispose: () => {
|
|
7755
|
-
|
|
8539
|
+
particleSystemGeneralContent.dispose();
|
|
8540
|
+
particleSystemAttractorsContent.dispose();
|
|
8541
|
+
particleSystemEmitterContent.dispose();
|
|
8542
|
+
particleSystemEmissionContent.dispose();
|
|
8543
|
+
particleSystemSizeContent.dispose();
|
|
8544
|
+
particleSystemLifetimeContent.dispose();
|
|
8545
|
+
particleSystemColorContent.dispose();
|
|
8546
|
+
particleSystemRotationContent.dispose();
|
|
8547
|
+
particleSystemSpritesheetContent.dispose();
|
|
7756
8548
|
},
|
|
7757
8549
|
};
|
|
7758
8550
|
},
|
|
@@ -8178,8 +8970,7 @@ const SpinButtonPropertyLine = (props) => {
|
|
|
8178
8970
|
|
|
8179
8971
|
const SpriteManagerGeneralProperties = (props) => {
|
|
8180
8972
|
const { spriteManager, selectionService } = props;
|
|
8181
|
-
|
|
8182
|
-
return (jsxs(Fragment, { children: [jsx(TextPropertyLine, { label: "Capacity", value: spriteManager.capacity.toString() }), jsx(LinkToEntityPropertyLine, { label: "Texture", entity: texture, selectionService: selectionService })] }));
|
|
8973
|
+
return (jsxs(Fragment, { children: [jsx(TextPropertyLine, { label: "Capacity", value: spriteManager.capacity.toString() }), jsx(BoundProperty, { component: TextureSelectorPropertyLine, label: "Texture", target: spriteManager, propertyKey: "texture", scene: spriteManager.scene, onLink: (texture) => (selectionService.selectedEntity = texture) })] }));
|
|
8183
8974
|
};
|
|
8184
8975
|
const SpriteManagerOtherProperties = (props) => {
|
|
8185
8976
|
const { spriteManager } = props;
|
|
@@ -12412,4 +13203,4 @@ const TextAreaPropertyLine = (props) => {
|
|
|
12412
13203
|
AttachDebugLayer();
|
|
12413
13204
|
|
|
12414
13205
|
export { useSidePaneDockOverrides as $, Accordion as A, ButtonLine as B, Collapse as C, DebugServiceIdentity as D, ExtensibleAccordion as E, FileUploadLine as F, useVector3Property as G, useColor3Property as H, Inspector as I, useColor4Property as J, useQuaternionProperty as K, Link as L, MakeLazyComponent as M, NumberDropdownPropertyLine as N, MakePropertyHook as O, Popover as P, useInterceptObservable as Q, useEventfulState as R, SwitchPropertyLine as S, ToolsServiceIdentity as T, useObservableCollection as U, Vector3PropertyLine as V, useOrderedObservableCollection as W, usePollingObservable as X, useResource as Y, useAsyncResource as Z, useCompactMode as _, SyncedSliderPropertyLine as a, useAngleConverters as a0, MakeTeachingMoment as a1, MakeDialogTeachingMoment as a2, InterceptFunction as a3, GetPropertyDescriptor as a4, IsPropertyReadonly as a5, InterceptProperty as a6, ObservableCollection as a7, ConstructorFactory as a8, SelectionServiceIdentity as a9, TextInput as aA, ToggleButton as aB, ChildWindow as aC, FactorGradientList as aD, Color3GradientList as aE, Color4GradientList as aF, Pane as aG, BooleanBadgePropertyLine as aH, Color3PropertyLine as aI, Color4PropertyLine as aJ, HexPropertyLine as aK, NumberInputPropertyLine as aL, LinkPropertyLine as aM, PropertyLine as aN, LineContainer as aO, PlaceholderPropertyLine as aP, StringifiedPropertyLine as aQ, TextAreaPropertyLine as aR, TextPropertyLine as aS, RotationVectorPropertyLine as aT, QuaternionPropertyLine as aU, Vector2PropertyLine as aV, Vector4PropertyLine as aW, SelectionServiceDefinition as aa, SettingsContextIdentity as ab, ShowInspector as ac, Checkbox as ad, ColorPickerPopup as ae, InputHexField as af, InputHsvField as ag, ComboBox as ah, DraggableLine as ai, Dropdown as aj, NumberDropdown as ak, StringDropdown as al, FactorGradientComponent as am, Color3GradientComponent as an, Color4GradientComponent as ao, ColorStepGradientComponent as ap, InfoLabel as aq, List as ar, MessageBar as as, PositionedPopover as at, SearchBar as au, SearchBox as av, SpinButton as aw, Switch as ax, SyncedSliderInput as ay, Textarea as az, Button as b, TextInputPropertyLine as c, SpinButtonPropertyLine as d, CheckboxPropertyLine as e, ShellServiceIdentity as f, SceneContextIdentity as g, AccordionSection as h, useExtensionManager as i, MakePopoverTeachingMoment as j, TeachingMoment as k, SidePaneContainer as l, PropertiesServiceIdentity as m, SceneExplorerServiceIdentity as n, SettingsServiceIdentity as o, StatsServiceIdentity as p, ConvertOptions as q, AttachDebugLayer as r, DetachDebugLayer as s, StringDropdownPropertyLine as t, useObservableState as u, BoundProperty as v, LinkToEntityPropertyLine as w, Theme as x, BuiltInsExtensionFeed as y, useProperty as z };
|
|
12415
|
-
//# sourceMappingURL=index-
|
|
13206
|
+
//# sourceMappingURL=index-bFqtVcnb.js.map
|