151 lines
4.4 KiB
TypeScript
151 lines
4.4 KiB
TypeScript
import type {
|
|
RuntimeResolvedControlChannelValue,
|
|
RuntimeResolvedDiscreteControlState
|
|
} from "../controls/control-surface";
|
|
|
|
import type { RuntimeSceneDefinition } from "./runtime-scene-build";
|
|
|
|
function mutateRuntimeLight(
|
|
runtimeScene: RuntimeSceneDefinition,
|
|
entityId: string,
|
|
mutate: (
|
|
light:
|
|
| RuntimeSceneDefinition["localLights"]["pointLights"][number]
|
|
| RuntimeSceneDefinition["localLights"]["spotLights"][number]
|
|
) => void
|
|
) {
|
|
const pointLight = runtimeScene.localLights.pointLights.find(
|
|
(candidate) => candidate.entityId === entityId
|
|
);
|
|
|
|
if (pointLight !== undefined) {
|
|
mutate(pointLight);
|
|
return;
|
|
}
|
|
|
|
const spotLight = runtimeScene.localLights.spotLights.find(
|
|
(candidate) => candidate.entityId === entityId
|
|
);
|
|
|
|
if (spotLight !== undefined) {
|
|
mutate(spotLight);
|
|
}
|
|
}
|
|
|
|
function applyResolvedDiscreteControlStateToRuntimeScene(
|
|
runtimeScene: RuntimeSceneDefinition,
|
|
state: RuntimeResolvedDiscreteControlState
|
|
) {
|
|
switch (state.type) {
|
|
case "projectTimePaused":
|
|
case "cameraRigOverride":
|
|
case "actorPresence":
|
|
case "actorAnimationPlayback":
|
|
case "actorPathAssignment":
|
|
// Runtime scene build already resolves scheduler-owned actor state.
|
|
return;
|
|
case "modelVisibility": {
|
|
const modelInstance = runtimeScene.modelInstances.find(
|
|
(candidate) => candidate.instanceId === state.target.modelInstanceId
|
|
);
|
|
|
|
if (modelInstance !== undefined) {
|
|
modelInstance.visible = state.value;
|
|
}
|
|
return;
|
|
}
|
|
case "soundPlayback": {
|
|
const soundEmitter = runtimeScene.entities.soundEmitters.find(
|
|
(candidate) => candidate.entityId === state.target.entityId
|
|
);
|
|
|
|
if (soundEmitter !== undefined) {
|
|
soundEmitter.autoplay = state.value;
|
|
}
|
|
return;
|
|
}
|
|
case "modelAnimationPlayback": {
|
|
const modelInstance = runtimeScene.modelInstances.find(
|
|
(candidate) => candidate.instanceId === state.target.modelInstanceId
|
|
);
|
|
|
|
if (modelInstance !== undefined) {
|
|
modelInstance.animationClipName = state.clipName ?? undefined;
|
|
modelInstance.animationAutoplay = state.clipName !== null;
|
|
modelInstance.animationLoop =
|
|
state.clipName === null ? undefined : state.loop;
|
|
}
|
|
return;
|
|
}
|
|
case "lightEnabled":
|
|
mutateRuntimeLight(runtimeScene, state.target.entityId, (light) => {
|
|
light.enabled = state.value;
|
|
});
|
|
return;
|
|
case "lightColor":
|
|
mutateRuntimeLight(runtimeScene, state.target.entityId, (light) => {
|
|
light.colorHex = state.value;
|
|
});
|
|
return;
|
|
case "interactionEnabled":
|
|
const interactable = runtimeScene.entities.interactables.find(
|
|
(candidate) => candidate.entityId === state.target.entityId
|
|
);
|
|
|
|
if (interactable !== undefined) {
|
|
interactable.interactionEnabled = state.value;
|
|
}
|
|
return;
|
|
case "ambientLightColor":
|
|
runtimeScene.world.ambientLight.colorHex = state.value;
|
|
return;
|
|
case "sunLightColor":
|
|
runtimeScene.world.sunLight.colorHex = state.value;
|
|
return;
|
|
}
|
|
}
|
|
|
|
function applyResolvedControlChannelValueToRuntimeScene(
|
|
runtimeScene: RuntimeSceneDefinition,
|
|
channelValue: RuntimeResolvedControlChannelValue
|
|
) {
|
|
switch (channelValue.type) {
|
|
case "lightIntensity":
|
|
mutateRuntimeLight(runtimeScene, channelValue.descriptor.target.entityId, (light) => {
|
|
light.intensity = channelValue.value;
|
|
});
|
|
return;
|
|
case "soundVolume": {
|
|
const soundEmitter = runtimeScene.entities.soundEmitters.find(
|
|
(candidate) =>
|
|
candidate.entityId === channelValue.descriptor.target.entityId
|
|
);
|
|
|
|
if (soundEmitter !== undefined) {
|
|
soundEmitter.volume = channelValue.value;
|
|
}
|
|
return;
|
|
}
|
|
case "ambientLightIntensity":
|
|
runtimeScene.world.ambientLight.intensity = channelValue.value;
|
|
return;
|
|
case "sunLightIntensity":
|
|
runtimeScene.world.sunLight.intensity = channelValue.value;
|
|
return;
|
|
}
|
|
}
|
|
|
|
export function applyResolvedControlStateToRuntimeScene(
|
|
runtimeScene: RuntimeSceneDefinition
|
|
): RuntimeSceneDefinition {
|
|
for (const state of runtimeScene.control.resolved.discrete) {
|
|
applyResolvedDiscreteControlStateToRuntimeScene(runtimeScene, state);
|
|
}
|
|
|
|
for (const channelValue of runtimeScene.control.resolved.channels) {
|
|
applyResolvedControlChannelValueToRuntimeScene(runtimeScene, channelValue);
|
|
}
|
|
|
|
return runtimeScene;
|
|
}
|