Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion editor/src/editor/layout/inspector/camera/free.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { FreeCamera, Node, Observer } from "babylonjs";
import { isFreeCamera } from "../../../../tools/guards/nodes";
import { onNodeModifiedObservable } from "../../../../tools/observables";

import { onGizmoNodeChangedObservable } from "../../preview/gizmo";
import { onGizmoNodeChangedObservable } from "../../preview/gizmo/gizmo";

import { IEditorInspectorImplementationProps } from "../inspector";

Expand Down
4 changes: 3 additions & 1 deletion editor/src/editor/layout/inspector/decals/decals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ export class EditorDecalsInspector extends Component<IEditorDecalsInspectorProps
}

private _handleUpdateCurrentDecalMesh(): void {
if (!EditorDecalsInspector._lastPickedMesh || !EditorDecalsInspector._lastPickPosition || !this.state.material) {
if (!EditorDecalsInspector._lastPickedMesh || !EditorDecalsInspector._lastPickPosition || !this.state.material || !this.state.ctrlOrMetaKeyDown) {
return;
}

Expand All @@ -295,6 +295,7 @@ export class EditorDecalsInspector extends Component<IEditorDecalsInspectorProps
normal: EditorDecalsInspector._lastPickedNormal ?? undefined,
});

this._decalMesh.isPickable = false;
this._decalMesh.receiveShadows = true;
this._decalMesh.visibility = this.state.ctrlOrMetaKeyDown ? 1 : 0.35;

Expand Down Expand Up @@ -332,6 +333,7 @@ export class EditorDecalsInspector extends Component<IEditorDecalsInspectorProps
decalMesh.name = this.state.material!.name;
decalMesh.id = Tools.RandomId();
decalMesh.uniqueId = UniqueNumber.Get();
decalMesh.isPickable = false;

decalMesh.metadata = {
decal: {
Expand Down
2 changes: 1 addition & 1 deletion editor/src/editor/layout/inspector/mesh/mesh.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import { EditorInspectorSectionField } from "../fields/section";
import { ScriptInspectorComponent } from "../script/script";
import { CustomMetadataInspector } from "../metadata/custom-metadata";

import { onGizmoNodeChangedObservable } from "../../preview/gizmo";
import { onGizmoNodeChangedObservable } from "../../preview/gizmo/gizmo";

import { EditorTransformNodeInspector } from "../transform";
import { IEditorInspectorImplementationProps } from "../inspector";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { computeSpriteManagerPreviews } from "../../../../tools/sprite/preview";

import { getProjectAssetsRootUrl } from "../../../../project/configuration";

import { onGizmoNodeChangedObservable } from "../../preview/gizmo";
import { onGizmoNodeChangedObservable } from "../../preview/gizmo/gizmo";

import { ScriptInspectorComponent } from "../script/script";

Expand Down
2 changes: 1 addition & 1 deletion editor/src/editor/layout/inspector/sprites/sprite-map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { Button } from "../../../../ui/shadcn/ui/button";

import { SpriteMapNode } from "../../../nodes/sprite-map";

import { onGizmoNodeChangedObservable } from "../../preview/gizmo";
import { onGizmoNodeChangedObservable } from "../../preview/gizmo/gizmo";

import { registerUndoRedo } from "../../../../tools/undoredo";
import { isSpriteMapNode } from "../../../../tools/guards/sprites";
Expand Down
2 changes: 1 addition & 1 deletion editor/src/editor/layout/inspector/sprites/sprite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { computeSpriteManagerPreviews } from "../../../../tools/sprite/preview";

import { SpriteManagerNode } from "../../../nodes/sprite-manager";

import { onGizmoNodeChangedObservable } from "../../preview/gizmo";
import { onGizmoNodeChangedObservable } from "../../preview/gizmo/gizmo";

import { ScriptInspectorComponent } from "../script/script";

Expand Down
2 changes: 1 addition & 1 deletion editor/src/editor/layout/inspector/transform.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { EditorInspectorSectionField } from "./fields/section";
import { ScriptInspectorComponent } from "./script/script";
import { CustomMetadataInspector } from "./metadata/custom-metadata";

import { onGizmoNodeChangedObservable } from "../preview/gizmo";
import { onGizmoNodeChangedObservable } from "../preview/gizmo/gizmo";

import { IEditorInspectorImplementationProps } from "./inspector";
import { EditorInspectorSwitchField } from "./fields/switch";
Expand Down
183 changes: 28 additions & 155 deletions editor/src/editor/layout/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Grid } from "react-loader-spinner";

import { FaCheck } from "react-icons/fa6";
import { IoIosStats } from "react-icons/io";
import { LuGrid3X3, LuMove3D, LuRotate3D, LuScale3D, LuScaling, LuRotateCw } from "react-icons/lu";
import { LuMove3D, LuRotate3D, LuScale3D } from "react-icons/lu";
import { GiArrowCursor, GiTeapot, GiWireframeGlobe } from "react-icons/gi";

import {
Expand Down Expand Up @@ -38,12 +38,16 @@ import {
Tools,
} from "babylonjs";

import { SpinnerUIComponent } from "../../ui/spinner";

import { Button } from "../../ui/shadcn/ui/button";
import { Toggle } from "../../ui/shadcn/ui/toggle";
import { EditorInspectorNumberField } from "./inspector/fields/number";
import { Progress } from "../../ui/shadcn/ui/progress";
import { Separator } from "../../ui/shadcn/ui/separator";
import { ToolbarRadioGroup, ToolbarRadioGroupItem } from "../../ui/shadcn/ui/toolbar-radio-group";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../../ui/shadcn/ui/tooltip";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/shadcn/ui/select";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "../../ui/shadcn/ui/dropdown-menu";

import { Editor } from "../main";

Expand All @@ -61,24 +65,13 @@ import { getCameraFocusPositionFor } from "../../tools/camera/focus";
import { ITweenConfiguration, Tween } from "../../tools/animation/tween";
import { checkProjectCachedCompressedTextures } from "../../tools/assets/ktx";
import { createSceneLink, getRootSceneLink } from "../../tools/scene/scene-link";
import {
defaultGizmoSnapPreferences,
gizmoSnapMinStep,
IGizmoSnapPreferences,
roundGizmoSnapSteps,
} from "../../tools/gizmo-snap-preferences";
import { UniqueNumber, waitNextAnimationFrame, waitUntil } from "../../tools/tools";
import { isSprite, isSpriteManagerNode, isSpriteMapNode } from "../../tools/guards/sprites";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "../../ui/shadcn/ui/dropdown-menu";
import { Popover, PopoverContent, PopoverTrigger } from "../../ui/shadcn/ui/popover";
import { isAbstractMesh, isAnyTransformNode, isCamera, isCollisionInstancedMesh, isCollisionMesh, isInstancedMesh, isLight, isMesh, isNode } from "../../tools/guards/nodes";
import { defaultGizmoSnapPreferences, IGizmoSnapPreferences, roundGizmoSnapSteps } from "../../tools/scene/gizmo";
import { isAbstractMesh, isAnyTransformNode, isCamera, isCollisionInstancedMesh, isCollisionMesh, isLight, isNode } from "../../tools/guards/nodes";

import { EditorCamera } from "../nodes/camera";

import { SpinnerUIComponent } from "../../ui/spinner";
import { Separator } from "../../ui/shadcn/ui/separator";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../../ui/shadcn/ui/tooltip";

import { saveRenderingConfigurationForCamera } from "../rendering/tools";
import { disposeVLSPostProcess, parseVLSPostProcess, vlsPostProcessCameraConfigurations } from "../rendering/vls";
import { disposeTAARenderingPipeline, parseTAARenderingPipeline, taaPipelineCameraConfigurations } from "../rendering/taa";
Expand All @@ -89,12 +82,14 @@ import { defaultPipelineCameraConfigurations, disposeDefaultRenderingPipeline, p

import { EditorGraphContextMenu } from "./graph/context-menu";

import { EditorPreviewGizmo } from "./preview/gizmo";
import { EditorPreviewIcons } from "./preview/icons";
import { EditorPreviewCamera } from "./preview/camera";
import { EditorPreviewAxisHelper } from "./preview/axis";
import { EditorPreviewPlayComponent } from "./preview/play";

import { EditorPreviewGizmo } from "./preview/gizmo/gizmo";
import { EditorPreviewGizmoSettings } from "./preview/gizmo/settings";

import { Stats } from "./preview/stats/stats";
import { StatRow } from "./preview/stats/row";
import { StatsValuesType } from "./preview/stats/types";
Expand Down Expand Up @@ -129,15 +124,14 @@ export interface IEditorPreviewState {
playEnabled: boolean;
playSceneLoadingProgress: number;

gizmoSnap: IGizmoSnapPreferences;
activeGizmo: "position" | "rotation" | "scaling" | "none";

/**
* Defines the fixed dimensions of the preview canvas.
* "fit" means the canvas will fit the entire panel container.
*/
fixedDimensions: "720p" | "1080p" | "4k" | "fit";

gizmoSnap: IGizmoSnapPreferences;
}

export class EditorPreview extends Component<IEditorPreviewProps, IEditorPreviewState> {
Expand Down Expand Up @@ -206,16 +200,6 @@ export class EditorPreview extends Component<IEditorPreviewProps, IEditorPreview
private _workingCanvas: HTMLCanvasElement | null = null;
private _mainView: EngineView | null = null;

/**
* Mutable holder for gizmo snap step fields; EditorInspectorNumberField writes via setInspectorEffectivePropertyValue.
* Synced from state when rendering the gizmo snap toolbar.
*/
private _gizmoSnapNumberFields: Pick<IGizmoSnapPreferences, "translationStep" | "rotationStepDegrees" | "scaleStep"> = {
translationStep: 0,
rotationStepDegrees: 0,
scaleStep: 0,
};

/** @internal */
public _previewCamera: Camera | null = null;

Expand Down Expand Up @@ -583,11 +567,13 @@ export class EditorPreview extends Component<IEditorPreviewProps, IEditorPreview

this.engine.runRenderLoop(() => {
if (this._renderScene && !this.play.state.playing) {
// TODO: remove this once fixed
// Bug report on forum: https://forum.babylonjs.com/t/multi-canvas-and-post-processes/59616/23
const ppRenderer = this.scene.prePassRenderer;
if (ppRenderer) {
ppRenderer.markAsDirty();
if (this._previewCamera) {
// TODO: remove this once fixed
// Bug report on forum: https://forum.babylonjs.com/t/multi-canvas-and-post-processes/59616/23
const ppRenderer = this.scene.prePassRenderer;
if (ppRenderer) {
ppRenderer.markAsDirty();
}
}

this.scene.render();
Expand Down Expand Up @@ -899,125 +885,12 @@ export class EditorPreview extends Component<IEditorPreviewProps, IEditorPreview
);
}

private _commitGizmoSnap(next: IGizmoSnapPreferences): void {
const normalized = roundGizmoSnapSteps(next);
this.setState({ gizmoSnap: normalized });
this.gizmo?.setSnapPreferences(normalized);
}

public updateGizmoSnapPreferences(prefs: IGizmoSnapPreferences): void {
this._commitGizmoSnap({ ...prefs });
}

private _getGizmoSnapToolbarControls(): ReactNode {
const snap = this.state.gizmoSnap;
const min = gizmoSnapMinStep;

this._gizmoSnapNumberFields.translationStep = snap.translationStep;
this._gizmoSnapNumberFields.rotationStepDegrees = snap.rotationStepDegrees;
this._gizmoSnapNumberFields.scaleStep = snap.scaleStep;

const bumpTranslation = (v: number) => this._commitGizmoSnap({ ...snap, translationStep: Math.max(min, v) });
const bumpRotation = (v: number) => this._commitGizmoSnap({ ...snap, rotationStepDegrees: Math.max(min, v) });
const bumpScale = (v: number) => this._commitGizmoSnap({ ...snap, scaleStep: Math.max(min, v) });

const snapRowClass = "grid grid-cols-[minmax(0,7rem)_auto_minmax(0,1fr)] items-center gap-3";
const snapToggleClass = (enabled: boolean) =>
`rounded-md border border-input h-9 w-9 px-0 shrink-0 justify-center shadow-sm ${enabled ? "bg-primary/20" : "bg-background"}`;

return (
<Popover>
<PopoverTrigger asChild>
<Button type="button" variant="outline" className="h-9 px-3 shrink-0 border-input bg-background shadow-sm">
Snap
</Button>
</PopoverTrigger>
<PopoverContent align="start" side="bottom" className="w-auto max-w-none min-w-[20rem] p-4">
<div className="flex flex-col gap-3">
<div className={snapRowClass}>
<div className="text-sm font-medium text-muted-foreground">Translation</div>
<Tooltip>
<TooltipTrigger asChild>
<Toggle
pressed={snap.translationEnabled}
onPressedChange={(on) => this._commitGizmoSnap({ ...snap, translationEnabled: on })}
className={snapToggleClass(snap.translationEnabled)}
aria-label="Translation grid snap"
>
<LuGrid3X3 className="h-4 w-4" />
</Toggle>
</TooltipTrigger>
<TooltipContent>Translation grid snap</TooltipContent>
</Tooltip>
<div className="min-w-0">
<EditorInspectorNumberField
object={this._gizmoSnapNumberFields}
property="translationStep"
noUndoRedo
step={0.01}
min={min}
onChange={(v) => bumpTranslation(v)}
/>
</div>
</div>

<div className={snapRowClass}>
<div className="text-sm font-medium text-muted-foreground">Rotation</div>
<Tooltip>
<TooltipTrigger asChild>
<Toggle
pressed={snap.rotationEnabled}
onPressedChange={(on) => this._commitGizmoSnap({ ...snap, rotationEnabled: on })}
className={snapToggleClass(snap.rotationEnabled)}
aria-label="Rotation snap"
>
<LuRotateCw className="h-4 w-4" />
</Toggle>
</TooltipTrigger>
<TooltipContent>Rotation snap (degrees)</TooltipContent>
</Tooltip>
<div className="min-w-0">
<EditorInspectorNumberField
object={this._gizmoSnapNumberFields}
property="rotationStepDegrees"
noUndoRedo
step={0.01}
min={min}
onChange={(v) => bumpRotation(v)}
/>
</div>
</div>

<div className={snapRowClass}>
<div className="text-sm font-medium text-muted-foreground">Scale</div>
<Tooltip>
<TooltipTrigger asChild>
<Toggle
pressed={snap.scaleEnabled}
onPressedChange={(on) => this._commitGizmoSnap({ ...snap, scaleEnabled: on })}
className={snapToggleClass(snap.scaleEnabled)}
aria-label="Scale snap"
>
<LuScaling className="h-4 w-4" />
</Toggle>
</TooltipTrigger>
<TooltipContent>Scale snap (incremental step)</TooltipContent>
</Tooltip>
<div className="min-w-0">
<EditorInspectorNumberField
object={this._gizmoSnapNumberFields}
property="scaleStep"
noUndoRedo
step={0.01}
min={min}
onChange={(v) => bumpScale(v)}
/>
</div>
</div>
</div>
</PopoverContent>
</Popover>
);
const normalized = roundGizmoSnapSteps(prefs);
this.gizmo?.setSnapPreferences(normalized);
this.setState({
gizmoSnap: normalized,
});
}

private _getEditToolbar(): ReactNode {
Expand Down Expand Up @@ -1085,6 +958,10 @@ export class EditorPreview extends Component<IEditorPreviewProps, IEditorPreview

<Separator orientation="vertical" className="mx-1 h-[24px]" />

<EditorPreviewGizmoSettings editor={this.props.editor} />

<Separator orientation="vertical" className="mx-1 h-[24px]" />

<Tooltip>
<TooltipTrigger asChild>
<Toggle
Expand All @@ -1103,10 +980,6 @@ export class EditorPreview extends Component<IEditorPreviewProps, IEditorPreview

<Separator orientation="vertical" className="mx-1 h-[24px]" />

{this._getGizmoSnapToolbarControls()}

<Separator orientation="vertical" className="mx-1 h-[24px]" />

<Select
value={this.gizmo?.getCoordinateMode().toString()}
onValueChange={(v) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ import {
Sprite,
} from "babylonjs";

import { defaultGizmoSnapPreferences, IGizmoSnapPreferences } from "../../../tools/gizmo-snap-preferences";
import { isSprite } from "../../../tools/guards/sprites";
import { registerUndoRedo } from "../../../tools/undoredo";
import { isNodeLocked } from "../../../tools/node/metadata";
import { isQuaternion, isVector3 } from "../../../tools/guards/math";
import { updateIblShadowsRenderPipeline } from "../../../tools/light/ibl";
import { isAbstractMesh, isCamera, isLight, isNode } from "../../../tools/guards/nodes";
import { updateLightShadowMapRefreshRate, updatePointLightShadowMapRenderListPredicate } from "../../../tools/light/shadows";
import { isSprite } from "../../../../tools/guards/sprites";
import { registerUndoRedo } from "../../../../tools/undoredo";
import { isNodeLocked } from "../../../../tools/node/metadata";
import { isQuaternion, isVector3 } from "../../../../tools/guards/math";
import { updateIblShadowsRenderPipeline } from "../../../../tools/light/ibl";
import { isAbstractMesh, isCamera, isLight, isNode } from "../../../../tools/guards/nodes";
import { defaultGizmoSnapPreferences, IGizmoSnapPreferences } from "../../../../tools/scene/gizmo";
import { updateLightShadowMapRefreshRate, updatePointLightShadowMapRenderListPredicate } from "../../../../tools/light/shadows";

export const onGizmoNodeChangedObservable = new Observable<Node | Sprite>();

Expand Down
Loading