11import { Divider , MenuItem , Select , Stack , TextField } from "@mui/material"
2- import { useCallback , useEffect , useRef , useState } from "react"
3- import * as THREE from "three "
2+ import { useCallback , useEffect , useMemo , useState } from "react"
3+ import { SelectMenuHeader } from "@/components/SelectMenu.tsx "
44import type MirabufSceneObject from "@/mirabuf/MirabufSceneObject"
55import EventSystem from "@/systems/EventSystem.ts"
66import PreferencesSystem from "@/systems/preferences/PreferencesSystem"
@@ -11,7 +11,13 @@ import ScrollView from "@/ui/components/ScrollView"
1111import { AddButton , DeleteButton , EditButton } from "@/ui/components/StyledComponents"
1212import TransformGizmoControl from "@/ui/components/TransformGizmoControl"
1313import type { ConfigurationSubpanelComponent } from "@/panels/configuring/assembly-config/ConfigTypes.ts"
14- import { useHoldPhysicsPause } from "@/util/ReactHooks.ts"
14+ import { useConfigurationSavedListener , useHoldPhysicsPause } from "@/util/ReactHooks.ts"
15+ import {
16+ useDirectionIndicatorMesh ,
17+ useFieldPointMarkers ,
18+ useFieldRelativeGizmoPosition ,
19+ useSyncIndicatorRotation ,
20+ } from "./FieldPointEditing"
1521
1622const RAD_TO_DEG = 180 / Math . PI
1723const DEG_TO_RAD = Math . PI / 180
@@ -44,12 +50,20 @@ interface ListViewProps {
4450const ListView : React . FC < ListViewProps > = ( { selectedField, points, onChange, onAdd, onEdit } ) => {
4551 const saveEvent = useCallback ( ( ) => persist ( points , selectedField ) , [ points , selectedField ] )
4652
47- useEffect ( ( ) => EventSystem . listen ( "ConfigurationSavedEvent" , saveEvent ) , [ saveEvent ] )
48- useEffect ( ( ) => {
49- persist ( points , selectedField )
50- } , [ selectedField , points ] )
51-
53+ useConfigurationSavedListener ( saveEvent )
5254 useHoldPhysicsPause ( )
55+ useEffect ( ( ) => persist ( points , selectedField ) , [ selectedField , points ] )
56+
57+ const markerPoints = useMemo (
58+ ( ) =>
59+ points . map ( p => ( {
60+ pos : p . pos ,
61+ yaw : p . look . type === "rotation" ? p . look . yaw : undefined ,
62+ pitch : p . look . type === "rotation" ? p . look . pitch : undefined ,
63+ } ) ) ,
64+ [ points ]
65+ )
66+ useFieldPointMarkers ( selectedField , markerPoints , "-z" )
5367
5468 return (
5569 < >
@@ -105,32 +119,35 @@ const EditView: React.FC<EditViewProps> = ({ selectedField, point, onSave }) =>
105119 const [ pitchDeg , setPitchDeg ] = useState (
106120 point . look . type === "rotation" ? Math . round ( point . look . pitch * RAD_TO_DEG ) : - 30
107121 )
108- const gizmoRef = useRef < GizmoSceneObject | undefined > ( undefined )
122+ const { gizmoRef, postGizmoCreation, readFieldRelativePosition } = useFieldRelativeGizmoPosition (
123+ selectedField ,
124+ point . pos
125+ )
126+ // Cameras look down their local -Z axis, so the indicator points -Z instead of the usual +Z "forward".
127+ const directionIndicatorMesh = useDirectionIndicatorMesh ( "-z" )
128+ useSyncIndicatorRotation ( directionIndicatorMesh , yawDeg * DEG_TO_RAD , pitchDeg * DEG_TO_RAD )
109129
110- const postGizmoCreation = useCallback (
130+ const setupGizmo = useCallback (
111131 ( gizmo : GizmoSceneObject ) => {
112- const fieldRef = selectedField . getXZPositionTransform ( )
113- gizmo . obj . position . set ( fieldRef . x + point . pos [ 0 ] , fieldRef . y + point . pos [ 1 ] , fieldRef . z + point . pos [ 2 ] )
132+ postGizmoCreation ( gizmo )
133+ gizmo . obj . add ( directionIndicatorMesh )
114134 } ,
115- [ selectedField , point . pos ]
135+ [ postGizmoCreation , directionIndicatorMesh ]
116136 )
117137
138+ useEffect ( ( ) => {
139+ directionIndicatorMesh . visible = lookType === "rotation"
140+ } , [ directionIndicatorMesh , lookType ] )
141+
118142 const buildPoint = useCallback ( ( ) : CameraPoint => {
119- let pos : [ number , number , number ] = [ point . pos [ 0 ] , point . pos [ 1 ] , point . pos [ 2 ] ]
120- if ( gizmoRef . current ) {
121- gizmoRef . current . obj . updateWorldMatrix ( true , false )
122- const worldPos = gizmoRef . current . obj . getWorldPosition ( new THREE . Vector3 ( ) )
123- const fieldRef = selectedField . getXZPositionTransform ( )
124- pos = [ worldPos . x - fieldRef . x , worldPos . y - fieldRef . y , worldPos . z - fieldRef . z ]
125- }
126143 const look : CameraLook =
127144 lookType === "field"
128145 ? { type : "field" }
129146 : { type : "rotation" , yaw : yawDeg * DEG_TO_RAD , pitch : pitchDeg * DEG_TO_RAD }
130- return { name, pos, look }
131- } , [ selectedField , point . pos , lookType , name , yawDeg , pitchDeg ] )
147+ return { name, pos : readFieldRelativePosition ( ) , look }
148+ } , [ readFieldRelativePosition , lookType , name , yawDeg , pitchDeg ] )
132149
133- useEffect ( ( ) => EventSystem . listen ( "ConfigurationSavedEvent" , ( ) => onSave ( buildPoint ( ) ) ) , [ buildPoint , onSave ] )
150+ useConfigurationSavedListener ( useCallback ( ( ) => onSave ( buildPoint ( ) ) , [ buildPoint , onSave ] ) )
134151 useHoldPhysicsPause ( )
135152
136153 return (
@@ -182,7 +199,7 @@ const EditView: React.FC<EditViewProps> = ({ selectedField, point, onSave }) =>
182199 defaultMode = "translate"
183200 rotateDisabled = { true }
184201 scaleDisabled = { true }
185- postGizmoCreation = { postGizmoCreation }
202+ postGizmoCreation = { setupGizmo }
186203 />
187204 </ Stack >
188205 )
@@ -229,11 +246,14 @@ const ConfigureCameraPointsInterface: ConfigurationSubpanelComponent = ({
229246 if ( editIndex !== undefined && points [ editIndex ] !== undefined ) {
230247 return (
231248 < >
232- < Stack direction = "row" minHeight = "30px" alignItems = "center" >
233- < Label size = "sm" className = "text-center mt-[4pt] mb-[2pt] mx-[5%]" >
234- Configuring Camera Position
235- </ Label >
236- </ Stack >
249+ < SelectMenuHeader
250+ label = { points [ editIndex ] . name }
251+ showBackButton = { true }
252+ onBackButton = { ( ) => {
253+ EventSystem . dispatch ( "ConfigurationSavedEvent" )
254+ setEditIndex ( undefined )
255+ } }
256+ />
237257 < Divider />
238258 < EditView
239259 selectedField = { selectedAssembly }
0 commit comments