Skip to content
This repository has been archived by the owner on Aug 21, 2024. It is now read-only.

Commit

Permalink
IR-2377 spin products (#10344)
Browse files Browse the repository at this point in the history
* wip on spinning ecommerce, drag detection in interactables

* helper functions and API for transform up, right, fwd. Can still call as TransformComponent.up(entity) but we can also call it on an instance of a transformcomponent (e.g. transform.up() )

* removing the helper functions we're not allowed to write

* updating how the helper functions work, removing the stored constants in favor of a returned "out" Vector

* wip on gizmo changes

* WIP on refactoring inputs

* adding ordering to InputComponent's useExecuteWithInput subsystems as part of the new InputExecutionSystemGroup

* button states updates

* dragging and rotating states hammered out, need to test and replace the logic in InteractableComponent in favor of drag detection inside of productComponent instead

* massive simplification of dragging and rotating events per button, simplified interactablecomponent based on this change, enables ecommerce interactions, gizmo cleanup

* reverting interaction alias changes

* adding inputSource Entity to button state

* no longer setting drag to false on mouse up, should reflect state similarly to pressed
camera orbit system now requires dragging to be true before it captures input and begins orbiting
InteractableComponent now requires dragging to be false to capture (this allows orbiting if you started mouseDown over an interactable)
EditorControlSystem no longer needs accumulator or checking mouse down vs up entity, just checks for no dragging on mouse up instead
no longer starting GizmoPlane with visibleComponent, this is managed in the TransformGizmoControlComponent when a control entity is dragged
simplified TransformGizmoControlComponent logical flow, now properly updates VisibleComponent on gizmoPlane

* prevent garbage generation per frame when checking pointer position before dragging is true
  • Loading branch information
SamMazerIR authored Jun 12, 2024
1 parent 731a6a0 commit 96d5e73
Show file tree
Hide file tree
Showing 10 changed files with 319 additions and 131 deletions.
70 changes: 35 additions & 35 deletions packages/editor/src/classes/TransformGizmoControlComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,11 @@ import {
Engine,
Entity,
getComponent,
getOptionalComponent,
InputSystemGroup,
removeComponent,
setComponent,
UndefinedEntity,
useComponent,
useEntityContext,
useExecute
useEntityContext
} from '@etherealengine/ecs'
import {
SnapMode,
Expand All @@ -47,14 +45,15 @@ import {
TransformSpace,
TransformSpaceType
} from '@etherealengine/engine/src/scene/constants/transformConstants'
import { matches, useMutableState } from '@etherealengine/hyperflux'
import { InputComponent } from '@etherealengine/spatial/src/input/components/InputComponent'
import { InputSourceComponent } from '@etherealengine/spatial/src/input/components/InputSourceComponent'
import { getState, matches, useMutableState } from '@etherealengine/hyperflux'
import { InputComponent, InputExecutionOrder } from '@etherealengine/spatial/src/input/components/InputComponent'
import { addObjectToGroup } from '@etherealengine/spatial/src/renderer/components/GroupComponent'
import { ObjectLayers } from '@etherealengine/spatial/src/renderer/constants/ObjectLayers'
import { RendererComponent } from '@etherealengine/spatial/src/renderer/WebGLRendererSystem'
import { TransformGizmoTagComponent } from '@etherealengine/spatial/src/transform/components/TransformComponent'

import { InputState } from '@etherealengine/spatial/src/input/state/InputState'
import { VisibleComponent } from '@etherealengine/spatial/src/renderer/components/VisibleComponent'
import { onPointerDown, onPointerHover, onPointerLost, onPointerMove, onPointerUp } from '../functions/gizmoHelper'
import { EditorHelperState } from '../services/EditorHelperState'
import { TransformGizmoVisualComponent } from './TransformGizmoVisualComponent'
Expand Down Expand Up @@ -126,43 +125,44 @@ export const TransformGizmoControlComponent = defineComponent({
getComponent(Engine.instance.viewerEntity, RendererComponent).renderer.domElement.style.touchAction = 'none' // disable touch scroll , hmm the editor window isnt scrollable anyways

const editorHelperState = useMutableState(EditorHelperState)
useExecute(
InputComponent.useExecuteWithInput(
() => {
const gizmoControlComponent = getComponent(gizmoControlEntity, TransformGizmoControlComponent)
if (!gizmoControlComponent.enabled) return
if (!gizmoControlComponent.visualEntity) return
if (!gizmoControlComponent.planeEntity) return

if (!gizmoControlComponent.enabled || !gizmoControlComponent.visualEntity || !gizmoControlComponent.planeEntity)
return

const visualComponent = getComponent(gizmoControlComponent.visualEntity, TransformGizmoVisualComponent)
const pickerInputSourceEntity = getComponent(visualComponent.picker[gizmoControlComponent.mode], InputComponent)
.inputSources[0]
const planeInputSourceEntity = getComponent(gizmoControlComponent.planeEntity, InputComponent).inputSources[0]
const pickerEntity = visualComponent.picker[gizmoControlComponent.mode]

if (pickerInputSourceEntity === undefined && planeInputSourceEntity === undefined) {
onPointerLost(gizmoControlEntity)
return
}
onPointerHover(gizmoControlEntity)

const pickerButtons = getOptionalComponent(pickerInputSourceEntity, InputSourceComponent)?.buttons
const planeButtons = getOptionalComponent(planeInputSourceEntity, InputSourceComponent)?.buttons

if (!pickerButtons && !planeButtons) {
onPointerLost(gizmoControlEntity)
return
}
if (!pickerButtons?.PrimaryClick && !planeButtons?.PrimaryClick) {
onPointerLost(gizmoControlEntity)
return
const pickerButtons = InputComponent.getMergedButtons(pickerEntity)
const planeButtons = InputComponent.getMergedButtons(gizmoControlComponent.planeEntity)

if (
(pickerButtons?.PrimaryClick?.pressed || planeButtons?.PrimaryClick?.pressed) &&
getState(InputState).capturingEntity === UndefinedEntity
) {
InputState.setCapturingEntity(pickerEntity)
onPointerMove(gizmoControlEntity)

//pointer down
if (pickerButtons?.PrimaryClick?.down) {
setComponent(gizmoControlComponent.planeEntity, VisibleComponent)
onPointerDown(gizmoControlEntity)
}

if (planeButtons?.PrimaryClick?.up || pickerButtons?.PrimaryClick?.up) {
onPointerUp(gizmoControlEntity)
onPointerLost(gizmoControlEntity)
onPointerLost(gizmoControlEntity)
removeComponent(gizmoControlComponent.planeEntity, VisibleComponent)
}
}

if (!pickerButtons?.PrimaryClick?.touched && !planeButtons?.PrimaryClick?.touched) return

onPointerMove(gizmoControlEntity)
if (planeButtons?.PrimaryClick?.up || pickerButtons?.PrimaryClick?.up) onPointerUp(gizmoControlEntity)
else if (pickerButtons?.PrimaryClick?.down) onPointerDown(gizmoControlEntity)
},
{ with: InputSystemGroup }
true,
InputExecutionOrder.Before
)

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export const TransformGizmoControlledComponent = defineComponent({

setComponent(gizmoPlaneEntity, NameComponent, 'gizmoPlaneEntity')
setComponent(gizmoPlaneEntity, TransformGizmoTagComponent)
setComponent(gizmoPlaneEntity, VisibleComponent) // needed for raycasting
//NOTE: VisibleComponent for gizmoPlaneEntity is managed in TransformGizmoControlComponent based on drag interaction

return () => {
removeEntity(gizmoControlEntity)
Expand Down
48 changes: 27 additions & 21 deletions packages/editor/src/systems/EditorControlSystem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import {
} from '@etherealengine/spatial/src/transform/components/EntityTree'

import { ModelComponent } from '@etherealengine/engine/src/scene/components/ModelComponent'
import { InputState } from '@etherealengine/spatial/src/input/state/InputState'
import { TransformGizmoControlComponent } from '../classes/TransformGizmoControlComponent'
import { TransformGizmoControlledComponent } from '../classes/TransformGizmoControlledComponent'
import { addMediaNode } from '../functions/addMediaNode'
Expand Down Expand Up @@ -236,6 +237,7 @@ const findIntersectObjects = (object: Object3D, excludeObjects?: Object3D[], exc
}

const inputQuery = defineQuery([InputSourceComponent])
let clickStartEntity = UndefinedEntity

const execute = () => {
const entity = AvatarComponent.getSelfAvatarEntity()
Expand Down Expand Up @@ -277,31 +279,35 @@ const execute = () => {
}

if (buttons.PrimaryClick?.pressed) {
primaryClickAccum += deltaSeconds
}
if (buttons.PrimaryClick?.up) {
primaryClickAccum = 0
}
if (primaryClickAccum <= 0.2) {
if (buttons.PrimaryClick?.up) {
let clickedEntity = InputSourceComponent.getClosestIntersectedEntity(inputSources[0])
if (buttons.PrimaryClick?.down) {
clickStartEntity = InputSourceComponent.getClosestIntersectedEntity(inputSources[0])
while (
!hasComponent(clickedEntity, SourceComponent) &&
getOptionalComponent(clickedEntity, EntityTreeComponent)?.parentEntity
!hasComponent(clickStartEntity, SourceComponent) &&
getOptionalComponent(clickStartEntity, EntityTreeComponent)?.parentEntity
) {
clickedEntity = getComponent(clickedEntity, EntityTreeComponent).parentEntity!
}
if (hasComponent(clickedEntity, SourceComponent)) {
const modelComponent = getAncestorWithComponent(clickedEntity, ModelComponent)
const ancestorModelEntity = modelComponent || clickedEntity
SelectionState.updateSelection([
getComponent(
SelectionState.getSelectedEntities()[0] === ancestorModelEntity ? clickedEntity : ancestorModelEntity,
UUIDComponent
)
])
clickStartEntity = getComponent(clickStartEntity, EntityTreeComponent).parentEntity!
}
}
const capturingEntity = getState(InputState).capturingEntity
if (capturingEntity !== UndefinedEntity && capturingEntity !== clickStartEntity) {
clickStartEntity = capturingEntity
}
}
if (buttons.PrimaryClick?.up && !buttons.PrimaryClick?.dragging) {
if (hasComponent(clickStartEntity, SourceComponent)) {
const modelComponent = getAncestorWithComponent(clickStartEntity, ModelComponent)
const ancestorModelEntity = modelComponent || clickStartEntity

console.log(
SelectionState.getSelectedEntities()[0] === ancestorModelEntity ? clickStartEntity : ancestorModelEntity
)
SelectionState.updateSelection([
getComponent(
SelectionState.getSelectedEntities()[0] === ancestorModelEntity ? clickStartEntity : ancestorModelEntity,
UUIDComponent
)
])
}
}
}

Expand Down
39 changes: 12 additions & 27 deletions packages/engine/src/interaction/components/InteractableComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ All portions of the code written by the Ethereal Engine team are Copyright © 20
Ethereal Engine. All Rights Reserved.
*/

import { MathUtils, Vector3 } from 'three'
import { MathUtils, Vector2, Vector3 } from 'three'
import matches from 'ts-matches'

import { isClient } from '@etherealengine/common/src/utils/getEnvironment'
Expand Down Expand Up @@ -86,6 +86,8 @@ export enum XRUIActivationType {
}

const xrDistVec3 = new Vector3()
const inputPointerPosition = new Vector2()
let inputPointerEntity = UndefinedEntity

const updateXrDistVec3 = (selfAvatarEntity: Entity) => {
//TODO change from using rigidbody to use the transform position (+ height of avatar)
Expand Down Expand Up @@ -288,18 +290,21 @@ export const InteractableComponent = defineComponent({
reactor: () => {
if (!isClient) return null
const entity = useEntityContext()
// const interactable = useComponent(entity, InteractableComponent)
const isEditing = useMutableState(EngineState).isEditing
// const hasFocus = useMutableState(EngineState).hasFocus

InputComponent.useExecuteWithInput(() => {
const buttons = InputComponent.getMergedButtons(entity)

if (buttons.Interact?.pressed) {
if (
buttons.Interact?.pressed &&
!buttons.Interact?.dragging &&
getState(InputState).capturingEntity === UndefinedEntity
) {
InputState.setCapturingEntity(entity)
}
if (buttons.Interact?.down) {
callInteractCallbacks(entity)

if (buttons.Interact?.up) {
callInteractCallbacks(entity)
}
}
}, true)

Expand All @@ -316,26 +321,6 @@ export const InteractableComponent = defineComponent({

return () => {}
}, [isEditing.value])

// useEffect(() => {
// if (isEditing.value || !input) return
// const canvas = getComponent(Engine.instance.viewerEntity, RendererComponent).canvas
// if (input.inputSources.length > 0) {
// canvas.style.cursor = 'pointer'
// }
// return () => {
// canvas.style.cursor = 'auto'
// }
// }, [input?.inputSources.length, isEditing.value])

// //handle highlighting when state is set
// useEffect(() => {
// if (!interactable.highlighted.value) return
// setComponent(entity, HighlightComponent)
// return () => {
// removeComponent(entity, HighlightComponent)
// }
// }, [interactable.highlighted])
return null
}
})
Expand Down
3 changes: 2 additions & 1 deletion packages/engine/src/scene/components/MountPointComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Ethereal Engine. All Rights Reserved.
import { useEffect } from 'react'
import { Vector3 } from 'three'

import { UUIDComponent } from '@etherealengine/ecs'
import { UndefinedEntity, UUIDComponent } from '@etherealengine/ecs'
import {
defineComponent,
getComponent,
Expand Down Expand Up @@ -77,6 +77,7 @@ const mountPointInteractMessages = {
const mountCallbackName = 'mountEntity'

const mountEntity = (avatarEntity: Entity, mountEntity: Entity) => {
if (avatarEntity === UndefinedEntity) return //No avatar found, likely in edit mode for now
const mountedEntities = getState(MountPointState)
if (mountedEntities[getComponent(mountEntity, UUIDComponent)]) return //already sitting, exiting

Expand Down
17 changes: 12 additions & 5 deletions packages/spatial/src/camera/systems/CameraOrbitSystem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ import {
getComponent,
getMutableComponent,
getOptionalComponent,
setComponent
InputSystemGroup,
setComponent,
UndefinedEntity
} from '@etherealengine/ecs'
import { getState } from '@etherealengine/hyperflux'
import { TransformComponent } from '@etherealengine/spatial'
Expand All @@ -47,7 +49,7 @@ import { EngineState } from '../../EngineState'
import { InputComponent } from '../../input/components/InputComponent'
import { InputPointerComponent } from '../../input/components/InputPointerComponent'
import { MouseScroll } from '../../input/state/ButtonState'
import { ClientInputSystem } from '../../input/systems/ClientInputSystem'
import { InputState } from '../../input/state/InputState'
import { RendererComponent } from '../../renderer/WebGLRendererSystem'
import { FlyControlComponent } from '../components/FlyControlComponent'

Expand Down Expand Up @@ -88,10 +90,15 @@ const execute = () => {
if (!inputPointerEntity && !cameraOrbit.refocus.value) continue

// TODO: replace w/ EnabledComponent or DisabledComponent in query
if (cameraOrbit.disabled.value || (cameraEid == Engine.instance.viewerEntity && !getState(EngineState).isEditing))
if (
cameraOrbit.disabled.value ||
getState(InputState).capturingEntity !== UndefinedEntity ||
(cameraEid == Engine.instance.viewerEntity && !getState(EngineState).isEditing)
)
continue

if (buttons.PrimaryClick?.pressed) {
if (buttons.PrimaryClick?.pressed && buttons.PrimaryClick?.dragging) {
InputState.setCapturingEntity(cameraEid)
cameraOrbit.isOrbiting.set(true)
}

Expand Down Expand Up @@ -199,6 +206,6 @@ const execute = () => {

export const CameraOrbitSystem = defineSystem({
uuid: 'ee.engine.CameraOrbitSystem',
insert: { after: ClientInputSystem },
insert: { after: InputSystemGroup },
execute
})
Loading

0 comments on commit 96d5e73

Please sign in to comment.