Add transform session command and core logic
This commit is contained in:
149
src/commands/commit-transform-session-command.ts
Normal file
149
src/commands/commit-transform-session-command.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import { createMoveBoxBrushCommand } from "./move-box-brush-command";
|
||||
import { createUpsertEntityCommand } from "./upsert-entity-command";
|
||||
import { createUpsertModelInstanceCommand } from "./upsert-model-instance-command";
|
||||
import type { EditorCommand } from "./command";
|
||||
import type { SceneDocument } from "../document/scene-document";
|
||||
import { createModelInstance } from "../assets/model-instances";
|
||||
import {
|
||||
createInteractableEntity,
|
||||
createPlayerStartEntity,
|
||||
createPointLightEntity,
|
||||
createSoundEmitterEntity,
|
||||
createSpotLightEntity,
|
||||
createTeleportTargetEntity,
|
||||
createTriggerVolumeEntity
|
||||
} from "../entities/entity-instances";
|
||||
import {
|
||||
getTransformOperationLabel,
|
||||
type ActiveTransformSession
|
||||
} from "../core/transform-session";
|
||||
|
||||
function createTransformCommandLabel(session: ActiveTransformSession): string {
|
||||
return `${getTransformOperationLabel(session.operation)} ${
|
||||
session.target.kind === "brush"
|
||||
? "box brush"
|
||||
: session.target.kind === "entity"
|
||||
? session.target.entityKind === "playerStart"
|
||||
? "player start"
|
||||
: session.target.entityKind === "pointLight"
|
||||
? "point light"
|
||||
: session.target.entityKind === "spotLight"
|
||||
? "spot light"
|
||||
: session.target.entityKind === "soundEmitter"
|
||||
? "sound emitter"
|
||||
: session.target.entityKind === "triggerVolume"
|
||||
? "trigger volume"
|
||||
: session.target.entityKind === "teleportTarget"
|
||||
? "teleport target"
|
||||
: "interactable"
|
||||
: "model instance"
|
||||
}`;
|
||||
}
|
||||
|
||||
export function createCommitTransformSessionCommand(document: SceneDocument, session: ActiveTransformSession): EditorCommand {
|
||||
switch (session.target.kind) {
|
||||
case "brush":
|
||||
if (session.preview.kind !== "brush" || session.operation !== "translate") {
|
||||
throw new Error("Brush transforms currently support translation only.");
|
||||
}
|
||||
|
||||
return createMoveBoxBrushCommand({
|
||||
brushId: session.target.brushId,
|
||||
center: session.preview.center
|
||||
});
|
||||
case "modelInstance": {
|
||||
if (session.preview.kind !== "modelInstance") {
|
||||
throw new Error("Model instance transform preview is invalid.");
|
||||
}
|
||||
|
||||
const modelInstance = document.modelInstances[session.target.modelInstanceId];
|
||||
|
||||
if (modelInstance === undefined) {
|
||||
throw new Error(`Model instance ${session.target.modelInstanceId} does not exist.`);
|
||||
}
|
||||
|
||||
return createUpsertModelInstanceCommand({
|
||||
modelInstance: createModelInstance({
|
||||
...modelInstance,
|
||||
position: session.preview.position,
|
||||
rotationDegrees: session.preview.rotationDegrees,
|
||||
scale: session.preview.scale
|
||||
}),
|
||||
label: createTransformCommandLabel(session)
|
||||
});
|
||||
}
|
||||
case "entity": {
|
||||
if (session.preview.kind !== "entity") {
|
||||
throw new Error("Entity transform preview is invalid.");
|
||||
}
|
||||
|
||||
const entity = document.entities[session.target.entityId];
|
||||
|
||||
if (entity === undefined) {
|
||||
throw new Error(`Entity ${session.target.entityId} does not exist.`);
|
||||
}
|
||||
|
||||
switch (entity.kind) {
|
||||
case "pointLight":
|
||||
return createUpsertEntityCommand({
|
||||
entity: createPointLightEntity({
|
||||
...entity,
|
||||
position: session.preview.position
|
||||
}),
|
||||
label: createTransformCommandLabel(session)
|
||||
});
|
||||
case "spotLight":
|
||||
return createUpsertEntityCommand({
|
||||
entity: createSpotLightEntity({
|
||||
...entity,
|
||||
position: session.preview.position,
|
||||
direction: session.preview.rotation.kind === "direction" ? session.preview.rotation.direction : entity.direction
|
||||
}),
|
||||
label: createTransformCommandLabel(session)
|
||||
});
|
||||
case "playerStart":
|
||||
return createUpsertEntityCommand({
|
||||
entity: createPlayerStartEntity({
|
||||
...entity,
|
||||
position: session.preview.position,
|
||||
yawDegrees: session.preview.rotation.kind === "yaw" ? session.preview.rotation.yawDegrees : entity.yawDegrees
|
||||
}),
|
||||
label: createTransformCommandLabel(session)
|
||||
});
|
||||
case "soundEmitter":
|
||||
return createUpsertEntityCommand({
|
||||
entity: createSoundEmitterEntity({
|
||||
...entity,
|
||||
position: session.preview.position
|
||||
}),
|
||||
label: createTransformCommandLabel(session)
|
||||
});
|
||||
case "triggerVolume":
|
||||
return createUpsertEntityCommand({
|
||||
entity: createTriggerVolumeEntity({
|
||||
...entity,
|
||||
position: session.preview.position
|
||||
}),
|
||||
label: createTransformCommandLabel(session)
|
||||
});
|
||||
case "teleportTarget":
|
||||
return createUpsertEntityCommand({
|
||||
entity: createTeleportTargetEntity({
|
||||
...entity,
|
||||
position: session.preview.position,
|
||||
yawDegrees: session.preview.rotation.kind === "yaw" ? session.preview.rotation.yawDegrees : entity.yawDegrees
|
||||
}),
|
||||
label: createTransformCommandLabel(session)
|
||||
});
|
||||
case "interactable":
|
||||
return createUpsertEntityCommand({
|
||||
entity: createInteractableEntity({
|
||||
...entity,
|
||||
position: session.preview.position
|
||||
}),
|
||||
label: createTransformCommandLabel(session)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,23 @@ export function cloneEditorSelection(selection: EditorSelection): EditorSelectio
|
||||
};
|
||||
}
|
||||
|
||||
export function areEditorSelectionsEqual(left: EditorSelection, right: EditorSelection): boolean {
|
||||
if (left.kind !== right.kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (left.kind) {
|
||||
case "none":
|
||||
return true;
|
||||
case "brushFace":
|
||||
return right.kind === "brushFace" && left.brushId === right.brushId && left.faceId === right.faceId;
|
||||
case "brushes":
|
||||
case "entities":
|
||||
case "modelInstances":
|
||||
return right.kind === left.kind && left.ids.length === right.ids.length && left.ids.every((id, index) => id === right.ids[index]);
|
||||
}
|
||||
}
|
||||
|
||||
export function getSingleSelectedBrushId(selection: EditorSelection): string | null {
|
||||
if (selection.kind === "brushFace") {
|
||||
return selection.brushId;
|
||||
|
||||
532
src/core/transform-session.ts
Normal file
532
src/core/transform-session.ts
Normal file
@@ -0,0 +1,532 @@
|
||||
import { createOpaqueId } from "./ids";
|
||||
import type { EditorSelection } from "./selection";
|
||||
import type { Vec3 } from "./vector";
|
||||
import type { SceneDocument } from "../document/scene-document";
|
||||
import {
|
||||
cloneEntityInstance,
|
||||
getEntityKindLabel,
|
||||
type EntityInstance,
|
||||
type EntityKind
|
||||
} from "../entities/entity-instances";
|
||||
import { cloneModelInstance, getModelInstanceKindLabel, type ModelInstance } from "../assets/model-instances";
|
||||
import type { ViewportPanelId } from "../viewport-three/viewport-layout";
|
||||
|
||||
export type TransformOperation = "translate" | "rotate" | "scale";
|
||||
export type TransformAxis = "x" | "y" | "z";
|
||||
export type TransformSessionSource = "keyboard" | "gizmo" | "toolbar";
|
||||
|
||||
export interface YawEntityRotationState {
|
||||
kind: "yaw";
|
||||
yawDegrees: number;
|
||||
}
|
||||
|
||||
export interface DirectionEntityRotationState {
|
||||
kind: "direction";
|
||||
direction: Vec3;
|
||||
}
|
||||
|
||||
export interface NoEntityRotationState {
|
||||
kind: "none";
|
||||
}
|
||||
|
||||
export type EntityTransformRotationState = NoEntityRotationState | YawEntityRotationState | DirectionEntityRotationState;
|
||||
|
||||
export interface BrushTransformTarget {
|
||||
kind: "brush";
|
||||
brushId: string;
|
||||
initialCenter: Vec3;
|
||||
}
|
||||
|
||||
export interface ModelInstanceTransformTarget {
|
||||
kind: "modelInstance";
|
||||
modelInstanceId: string;
|
||||
assetId: string;
|
||||
initialPosition: Vec3;
|
||||
initialRotationDegrees: Vec3;
|
||||
initialScale: Vec3;
|
||||
}
|
||||
|
||||
export interface EntityTransformTarget {
|
||||
kind: "entity";
|
||||
entityId: string;
|
||||
entityKind: EntityKind;
|
||||
initialPosition: Vec3;
|
||||
initialRotation: EntityTransformRotationState;
|
||||
}
|
||||
|
||||
export type TransformTarget = BrushTransformTarget | ModelInstanceTransformTarget | EntityTransformTarget;
|
||||
|
||||
export interface BrushTransformPreview {
|
||||
kind: "brush";
|
||||
center: Vec3;
|
||||
}
|
||||
|
||||
export interface ModelInstanceTransformPreview {
|
||||
kind: "modelInstance";
|
||||
position: Vec3;
|
||||
rotationDegrees: Vec3;
|
||||
scale: Vec3;
|
||||
}
|
||||
|
||||
export interface EntityTransformPreview {
|
||||
kind: "entity";
|
||||
position: Vec3;
|
||||
rotation: EntityTransformRotationState;
|
||||
}
|
||||
|
||||
export type TransformPreview = BrushTransformPreview | ModelInstanceTransformPreview | EntityTransformPreview;
|
||||
|
||||
export interface ActiveTransformSession {
|
||||
kind: "active";
|
||||
id: string;
|
||||
source: TransformSessionSource;
|
||||
sourcePanelId: ViewportPanelId;
|
||||
operation: TransformOperation;
|
||||
axisConstraint: TransformAxis | null;
|
||||
target: TransformTarget;
|
||||
preview: TransformPreview;
|
||||
}
|
||||
|
||||
export type TransformSessionState = ActiveTransformSession | { kind: "none" };
|
||||
|
||||
export interface TransformTargetResolution {
|
||||
target: TransformTarget | null;
|
||||
message: string | null;
|
||||
}
|
||||
|
||||
function cloneVec3(vector: Vec3): Vec3 {
|
||||
return {
|
||||
x: vector.x,
|
||||
y: vector.y,
|
||||
z: vector.z
|
||||
};
|
||||
}
|
||||
|
||||
function areVec3Equal(left: Vec3, right: Vec3): boolean {
|
||||
return left.x === right.x && left.y === right.y && left.z === right.z;
|
||||
}
|
||||
|
||||
function cloneEntityTransformRotationState(rotation: EntityTransformRotationState): EntityTransformRotationState {
|
||||
switch (rotation.kind) {
|
||||
case "none":
|
||||
return {
|
||||
kind: "none"
|
||||
};
|
||||
case "yaw":
|
||||
return {
|
||||
kind: "yaw",
|
||||
yawDegrees: rotation.yawDegrees
|
||||
};
|
||||
case "direction":
|
||||
return {
|
||||
kind: "direction",
|
||||
direction: cloneVec3(rotation.direction)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function areEntityTransformRotationsEqual(left: EntityTransformRotationState, right: EntityTransformRotationState): boolean {
|
||||
if (left.kind !== right.kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (left.kind) {
|
||||
case "none":
|
||||
return true;
|
||||
case "yaw":
|
||||
return right.kind === "yaw" && left.yawDegrees === right.yawDegrees;
|
||||
case "direction":
|
||||
return right.kind === "direction" && areVec3Equal(left.direction, right.direction);
|
||||
}
|
||||
}
|
||||
|
||||
export function createInactiveTransformSession(): TransformSessionState {
|
||||
return {
|
||||
kind: "none"
|
||||
};
|
||||
}
|
||||
|
||||
export function cloneTransformTarget(target: TransformTarget): TransformTarget {
|
||||
switch (target.kind) {
|
||||
case "brush":
|
||||
return {
|
||||
kind: "brush",
|
||||
brushId: target.brushId,
|
||||
initialCenter: cloneVec3(target.initialCenter)
|
||||
};
|
||||
case "modelInstance":
|
||||
return {
|
||||
kind: "modelInstance",
|
||||
modelInstanceId: target.modelInstanceId,
|
||||
assetId: target.assetId,
|
||||
initialPosition: cloneVec3(target.initialPosition),
|
||||
initialRotationDegrees: cloneVec3(target.initialRotationDegrees),
|
||||
initialScale: cloneVec3(target.initialScale)
|
||||
};
|
||||
case "entity":
|
||||
return {
|
||||
kind: "entity",
|
||||
entityId: target.entityId,
|
||||
entityKind: target.entityKind,
|
||||
initialPosition: cloneVec3(target.initialPosition),
|
||||
initialRotation: cloneEntityTransformRotationState(target.initialRotation)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function cloneTransformPreview(preview: TransformPreview): TransformPreview {
|
||||
switch (preview.kind) {
|
||||
case "brush":
|
||||
return {
|
||||
kind: "brush",
|
||||
center: cloneVec3(preview.center)
|
||||
};
|
||||
case "modelInstance":
|
||||
return {
|
||||
kind: "modelInstance",
|
||||
position: cloneVec3(preview.position),
|
||||
rotationDegrees: cloneVec3(preview.rotationDegrees),
|
||||
scale: cloneVec3(preview.scale)
|
||||
};
|
||||
case "entity":
|
||||
return {
|
||||
kind: "entity",
|
||||
position: cloneVec3(preview.position),
|
||||
rotation: cloneEntityTransformRotationState(preview.rotation)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function cloneTransformSession(session: TransformSessionState): TransformSessionState {
|
||||
if (session.kind === "none") {
|
||||
return session;
|
||||
}
|
||||
|
||||
return {
|
||||
kind: "active",
|
||||
id: session.id,
|
||||
source: session.source,
|
||||
sourcePanelId: session.sourcePanelId,
|
||||
operation: session.operation,
|
||||
axisConstraint: session.axisConstraint,
|
||||
target: cloneTransformTarget(session.target),
|
||||
preview: cloneTransformPreview(session.preview)
|
||||
};
|
||||
}
|
||||
|
||||
export function areTransformSessionsEqual(left: TransformSessionState, right: TransformSessionState): boolean {
|
||||
if (left.kind !== right.kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (left.kind === "none" || right.kind === "none") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (
|
||||
left.id === right.id &&
|
||||
left.source === right.source &&
|
||||
left.sourcePanelId === right.sourcePanelId &&
|
||||
left.operation === right.operation &&
|
||||
left.axisConstraint === right.axisConstraint &&
|
||||
areTransformTargetsEqual(left.target, right.target) &&
|
||||
areTransformPreviewsEqual(left.preview, right.preview)
|
||||
);
|
||||
}
|
||||
|
||||
function areTransformTargetsEqual(left: TransformTarget, right: TransformTarget): boolean {
|
||||
if (left.kind !== right.kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (left.kind) {
|
||||
case "brush":
|
||||
return right.kind === "brush" && left.brushId === right.brushId && areVec3Equal(left.initialCenter, right.initialCenter);
|
||||
case "modelInstance":
|
||||
return (
|
||||
right.kind === "modelInstance" &&
|
||||
left.modelInstanceId === right.modelInstanceId &&
|
||||
left.assetId === right.assetId &&
|
||||
areVec3Equal(left.initialPosition, right.initialPosition) &&
|
||||
areVec3Equal(left.initialRotationDegrees, right.initialRotationDegrees) &&
|
||||
areVec3Equal(left.initialScale, right.initialScale)
|
||||
);
|
||||
case "entity":
|
||||
return (
|
||||
right.kind === "entity" &&
|
||||
left.entityId === right.entityId &&
|
||||
left.entityKind === right.entityKind &&
|
||||
areVec3Equal(left.initialPosition, right.initialPosition) &&
|
||||
areEntityTransformRotationsEqual(left.initialRotation, right.initialRotation)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function areTransformPreviewsEqual(left: TransformPreview, right: TransformPreview): boolean {
|
||||
if (left.kind !== right.kind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (left.kind) {
|
||||
case "brush":
|
||||
return right.kind === "brush" && areVec3Equal(left.center, right.center);
|
||||
case "modelInstance":
|
||||
return (
|
||||
right.kind === "modelInstance" &&
|
||||
areVec3Equal(left.position, right.position) &&
|
||||
areVec3Equal(left.rotationDegrees, right.rotationDegrees) &&
|
||||
areVec3Equal(left.scale, right.scale)
|
||||
);
|
||||
case "entity":
|
||||
return right.kind === "entity" && areVec3Equal(left.position, right.position) && areEntityTransformRotationsEqual(left.rotation, right.rotation);
|
||||
}
|
||||
}
|
||||
|
||||
export function createTransformSession(options: {
|
||||
source: TransformSessionSource;
|
||||
sourcePanelId: ViewportPanelId;
|
||||
operation: TransformOperation;
|
||||
axisConstraint?: TransformAxis | null;
|
||||
target: TransformTarget;
|
||||
}): ActiveTransformSession {
|
||||
return {
|
||||
kind: "active",
|
||||
id: createOpaqueId("transform-session"),
|
||||
source: options.source,
|
||||
sourcePanelId: options.sourcePanelId,
|
||||
operation: options.operation,
|
||||
axisConstraint: options.axisConstraint ?? null,
|
||||
target: cloneTransformTarget(options.target),
|
||||
preview: createTransformPreviewFromTarget(options.target)
|
||||
};
|
||||
}
|
||||
|
||||
export function createTransformPreviewFromTarget(target: TransformTarget): TransformPreview {
|
||||
switch (target.kind) {
|
||||
case "brush":
|
||||
return {
|
||||
kind: "brush",
|
||||
center: cloneVec3(target.initialCenter)
|
||||
};
|
||||
case "modelInstance":
|
||||
return {
|
||||
kind: "modelInstance",
|
||||
position: cloneVec3(target.initialPosition),
|
||||
rotationDegrees: cloneVec3(target.initialRotationDegrees),
|
||||
scale: cloneVec3(target.initialScale)
|
||||
};
|
||||
case "entity":
|
||||
return {
|
||||
kind: "entity",
|
||||
position: cloneVec3(target.initialPosition),
|
||||
rotation: cloneEntityTransformRotationState(target.initialRotation)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function doesTransformSessionChangeTarget(session: ActiveTransformSession): boolean {
|
||||
switch (session.target.kind) {
|
||||
case "brush":
|
||||
return session.preview.kind === "brush" && !areVec3Equal(session.preview.center, session.target.initialCenter);
|
||||
case "modelInstance":
|
||||
return (
|
||||
session.preview.kind === "modelInstance" &&
|
||||
(!areVec3Equal(session.preview.position, session.target.initialPosition) ||
|
||||
!areVec3Equal(session.preview.rotationDegrees, session.target.initialRotationDegrees) ||
|
||||
!areVec3Equal(session.preview.scale, session.target.initialScale))
|
||||
);
|
||||
case "entity":
|
||||
return (
|
||||
session.preview.kind === "entity" &&
|
||||
(!areVec3Equal(session.preview.position, session.target.initialPosition) ||
|
||||
!areEntityTransformRotationsEqual(session.preview.rotation, session.target.initialRotation))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function getTransformOperationLabel(operation: TransformOperation): string {
|
||||
switch (operation) {
|
||||
case "translate":
|
||||
return "Move";
|
||||
case "rotate":
|
||||
return "Rotate";
|
||||
case "scale":
|
||||
return "Scale";
|
||||
}
|
||||
}
|
||||
|
||||
export function getTransformAxisLabel(axis: TransformAxis): string {
|
||||
return axis.toUpperCase();
|
||||
}
|
||||
|
||||
export function getTransformTargetLabel(target: TransformTarget): string {
|
||||
switch (target.kind) {
|
||||
case "brush":
|
||||
return "Box Brush";
|
||||
case "modelInstance":
|
||||
return getModelInstanceKindLabel();
|
||||
case "entity":
|
||||
return getEntityKindLabel(target.entityKind);
|
||||
}
|
||||
}
|
||||
|
||||
export function getSupportedTransformOperations(target: TransformTarget): TransformOperation[] {
|
||||
switch (target.kind) {
|
||||
case "brush":
|
||||
return ["translate"];
|
||||
case "modelInstance":
|
||||
return ["translate", "rotate", "scale"];
|
||||
case "entity":
|
||||
return target.initialRotation.kind === "none" ? ["translate"] : ["translate", "rotate"];
|
||||
}
|
||||
}
|
||||
|
||||
export function supportsTransformOperation(target: TransformTarget, operation: TransformOperation): boolean {
|
||||
return getSupportedTransformOperations(target).includes(operation);
|
||||
}
|
||||
|
||||
export function supportsTransformAxisConstraint(session: ActiveTransformSession, axis: TransformAxis): boolean {
|
||||
switch (session.operation) {
|
||||
case "translate":
|
||||
return true;
|
||||
case "scale":
|
||||
return session.target.kind === "modelInstance";
|
||||
case "rotate":
|
||||
if (session.target.kind === "entity" && session.target.initialRotation.kind === "yaw") {
|
||||
return axis === "y";
|
||||
}
|
||||
|
||||
return session.target.kind !== "brush";
|
||||
}
|
||||
}
|
||||
|
||||
function resolveEntityRotation(entity: EntityInstance): EntityTransformRotationState {
|
||||
switch (entity.kind) {
|
||||
case "playerStart":
|
||||
case "teleportTarget":
|
||||
return {
|
||||
kind: "yaw",
|
||||
yawDegrees: entity.yawDegrees
|
||||
};
|
||||
case "spotLight":
|
||||
return {
|
||||
kind: "direction",
|
||||
direction: cloneVec3(entity.direction)
|
||||
};
|
||||
case "pointLight":
|
||||
case "soundEmitter":
|
||||
case "triggerVolume":
|
||||
case "interactable":
|
||||
return {
|
||||
kind: "none"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function createBrushTransformTarget(document: SceneDocument, brushId: string): TransformTargetResolution {
|
||||
const brush = document.brushes[brushId];
|
||||
|
||||
if (brush === undefined || brush.kind !== "box") {
|
||||
return {
|
||||
target: null,
|
||||
message: "Select a supported box brush before transforming it."
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
target: {
|
||||
kind: "brush",
|
||||
brushId: brush.id,
|
||||
initialCenter: cloneVec3(brush.center)
|
||||
},
|
||||
message: null
|
||||
};
|
||||
}
|
||||
|
||||
function createEntityTransformTarget(document: SceneDocument, entityId: string): TransformTargetResolution {
|
||||
const entity = document.entities[entityId];
|
||||
|
||||
if (entity === undefined) {
|
||||
return {
|
||||
target: null,
|
||||
message: "Select an authored entity before transforming it."
|
||||
};
|
||||
}
|
||||
|
||||
const clonedEntity = cloneEntityInstance(entity);
|
||||
|
||||
return {
|
||||
target: {
|
||||
kind: "entity",
|
||||
entityId: clonedEntity.id,
|
||||
entityKind: clonedEntity.kind,
|
||||
initialPosition: cloneVec3(clonedEntity.position),
|
||||
initialRotation: resolveEntityRotation(clonedEntity)
|
||||
},
|
||||
message: null
|
||||
};
|
||||
}
|
||||
|
||||
function createModelInstanceTransformTarget(document: SceneDocument, modelInstanceId: string): TransformTargetResolution {
|
||||
const modelInstance = document.modelInstances[modelInstanceId];
|
||||
|
||||
if (modelInstance === undefined) {
|
||||
return {
|
||||
target: null,
|
||||
message: "Select a model instance before transforming it."
|
||||
};
|
||||
}
|
||||
|
||||
const clonedModelInstance = cloneModelInstance(modelInstance);
|
||||
|
||||
return {
|
||||
target: {
|
||||
kind: "modelInstance",
|
||||
modelInstanceId: clonedModelInstance.id,
|
||||
assetId: clonedModelInstance.assetId,
|
||||
initialPosition: cloneVec3(clonedModelInstance.position),
|
||||
initialRotationDegrees: cloneVec3(clonedModelInstance.rotationDegrees),
|
||||
initialScale: cloneVec3(clonedModelInstance.scale)
|
||||
},
|
||||
message: null
|
||||
};
|
||||
}
|
||||
|
||||
export function resolveTransformTarget(document: SceneDocument, selection: EditorSelection): TransformTargetResolution {
|
||||
switch (selection.kind) {
|
||||
case "none":
|
||||
return {
|
||||
target: null,
|
||||
message: "Select a single brush, entity, or model instance before transforming it."
|
||||
};
|
||||
case "brushFace":
|
||||
return createBrushTransformTarget(document, selection.brushId);
|
||||
case "brushes":
|
||||
if (selection.ids.length !== 1) {
|
||||
return {
|
||||
target: null,
|
||||
message: "Select a single brush before transforming it."
|
||||
};
|
||||
}
|
||||
|
||||
return createBrushTransformTarget(document, selection.ids[0]);
|
||||
case "entities":
|
||||
if (selection.ids.length !== 1) {
|
||||
return {
|
||||
target: null,
|
||||
message: "Select a single entity before transforming it."
|
||||
};
|
||||
}
|
||||
|
||||
return createEntityTransformTarget(document, selection.ids[0]);
|
||||
case "modelInstances":
|
||||
if (selection.ids.length !== 1) {
|
||||
return {
|
||||
target: null,
|
||||
message: "Select a single model instance before transforming it."
|
||||
};
|
||||
}
|
||||
|
||||
return createModelInstanceTransformTarget(document, selection.ids[0]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user