2024-02-14 08:03:20 +11:00
|
|
|
import { useRef, useEffect, useState } from 'react'
|
|
|
|
import { useModelingContext } from 'hooks/useModelingContext'
|
|
|
|
|
|
|
|
import { cameraMouseDragGuards } from 'lib/cameraControls'
|
2024-03-11 20:26:13 -04:00
|
|
|
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
|
2024-04-04 11:07:51 +11:00
|
|
|
import { ARROWHEAD, DEBUG_SHOW_BOTH_SCENES } from './sceneInfra'
|
2024-02-26 19:53:44 +11:00
|
|
|
import { ReactCameraProperties } from './CameraControls'
|
2024-02-14 08:03:20 +11:00
|
|
|
import { throttle } from 'lib/utils'
|
2024-03-22 16:55:30 +11:00
|
|
|
import { sceneInfra } from 'lib/singletons'
|
2024-04-04 11:07:51 +11:00
|
|
|
import {
|
|
|
|
EXTRA_SEGMENT_HANDLE,
|
|
|
|
PROFILE_START,
|
|
|
|
getParentGroup,
|
|
|
|
} from './sceneEntities'
|
2024-02-14 08:03:20 +11:00
|
|
|
|
|
|
|
function useShouldHideScene(): { hideClient: boolean; hideServer: boolean } {
|
|
|
|
const [isCamMoving, setIsCamMoving] = useState(false)
|
|
|
|
const [isTween, setIsTween] = useState(false)
|
|
|
|
|
|
|
|
const { state } = useModelingContext()
|
|
|
|
|
|
|
|
useEffect(() => {
|
2024-02-26 19:53:44 +11:00
|
|
|
sceneInfra.camControls.setIsCamMovingCallback((isMoving, isTween) => {
|
2024-02-14 08:03:20 +11:00
|
|
|
setIsCamMoving(isMoving)
|
|
|
|
setIsTween(isTween)
|
|
|
|
})
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
if (DEBUG_SHOW_BOTH_SCENES || !isCamMoving)
|
|
|
|
return { hideClient: false, hideServer: false }
|
2024-02-17 07:04:24 +11:00
|
|
|
let hideServer = state.matches('Sketch')
|
2024-02-14 08:03:20 +11:00
|
|
|
if (isTween) {
|
|
|
|
hideServer = false
|
|
|
|
}
|
|
|
|
|
|
|
|
return { hideClient: !hideServer, hideServer }
|
|
|
|
}
|
|
|
|
|
|
|
|
export const ClientSideScene = ({
|
|
|
|
cameraControls,
|
|
|
|
}: {
|
|
|
|
cameraControls: ReturnType<
|
2024-03-11 20:26:13 -04:00
|
|
|
typeof useSettingsAuthContext
|
2024-04-02 10:29:34 -04:00
|
|
|
>['settings']['context']['modeling']['mouseControls']['current']
|
2024-02-14 08:03:20 +11:00
|
|
|
}) => {
|
|
|
|
const canvasRef = useRef<HTMLDivElement>(null)
|
2024-04-04 11:07:51 +11:00
|
|
|
const { state, send, context } = useModelingContext()
|
2024-02-14 08:03:20 +11:00
|
|
|
const { hideClient, hideServer } = useShouldHideScene()
|
|
|
|
|
|
|
|
// Listen for changes to the camera controls setting
|
|
|
|
// and update the client-side scene's controls accordingly.
|
|
|
|
useEffect(() => {
|
2024-02-26 19:53:44 +11:00
|
|
|
sceneInfra.camControls.interactionGuards =
|
|
|
|
cameraMouseDragGuards[cameraControls]
|
2024-02-14 08:03:20 +11:00
|
|
|
}, [cameraControls])
|
|
|
|
useEffect(() => {
|
|
|
|
sceneInfra.updateOtherSelectionColors(
|
|
|
|
state?.context?.selectionRanges?.otherSelections || []
|
|
|
|
)
|
|
|
|
}, [state?.context?.selectionRanges?.otherSelections])
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (!canvasRef.current) return
|
|
|
|
const canvas = canvasRef.current
|
|
|
|
canvas.appendChild(sceneInfra.renderer.domElement)
|
|
|
|
sceneInfra.animate()
|
|
|
|
canvas.addEventListener('mousemove', sceneInfra.onMouseMove, false)
|
|
|
|
canvas.addEventListener('mousedown', sceneInfra.onMouseDown, false)
|
|
|
|
canvas.addEventListener('mouseup', sceneInfra.onMouseUp, false)
|
|
|
|
sceneInfra.setSend(send)
|
|
|
|
return () => {
|
|
|
|
canvas?.removeEventListener('mousemove', sceneInfra.onMouseMove)
|
|
|
|
canvas?.removeEventListener('mousedown', sceneInfra.onMouseDown)
|
|
|
|
canvas?.removeEventListener('mouseup', sceneInfra.onMouseUp)
|
|
|
|
}
|
|
|
|
}, [])
|
|
|
|
|
2024-04-04 11:07:51 +11:00
|
|
|
let cursor = 'default'
|
|
|
|
if (state.matches('Sketch')) {
|
|
|
|
if (
|
|
|
|
context.mouseState.type === 'isHovering' &&
|
|
|
|
getParentGroup(context.mouseState.on, [
|
|
|
|
ARROWHEAD,
|
|
|
|
EXTRA_SEGMENT_HANDLE,
|
|
|
|
PROFILE_START,
|
|
|
|
])
|
|
|
|
) {
|
|
|
|
cursor = 'move'
|
|
|
|
} else if (context.mouseState.type === 'isDragging') {
|
|
|
|
cursor = 'grabbing'
|
|
|
|
} else if (
|
|
|
|
state.matches('Sketch.Line tool') ||
|
|
|
|
state.matches('Sketch.Tangential arc to')
|
|
|
|
) {
|
|
|
|
cursor = 'crosshair'
|
|
|
|
} else {
|
|
|
|
cursor = 'default'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-14 08:03:20 +11:00
|
|
|
return (
|
|
|
|
<div
|
|
|
|
ref={canvasRef}
|
2024-04-04 11:07:51 +11:00
|
|
|
style={{ cursor: cursor }}
|
2024-02-14 08:03:20 +11:00
|
|
|
className={`absolute inset-0 h-full w-full transition-all duration-300 ${
|
|
|
|
hideClient ? 'opacity-0' : 'opacity-100'
|
|
|
|
} ${hideServer ? 'bg-black' : ''} ${
|
|
|
|
!hideClient && !hideServer && state.matches('Sketch')
|
|
|
|
? 'bg-black/80'
|
|
|
|
: ''
|
|
|
|
}`}
|
|
|
|
></div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const throttled = throttle((a: ReactCameraProperties) => {
|
|
|
|
if (a.type === 'perspective' && a.fov) {
|
2024-02-26 19:53:44 +11:00
|
|
|
sceneInfra.camControls.dollyZoom(a.fov)
|
2024-02-14 08:03:20 +11:00
|
|
|
}
|
|
|
|
}, 1000 / 15)
|
|
|
|
|
|
|
|
export const CamDebugSettings = () => {
|
2024-04-15 12:04:17 -04:00
|
|
|
const [camSettings, setCamSettings] = useState<ReactCameraProperties>(
|
|
|
|
sceneInfra.camControls.reactCameraProperties
|
|
|
|
)
|
2024-02-14 08:03:20 +11:00
|
|
|
const [fov, setFov] = useState(12)
|
|
|
|
|
|
|
|
useEffect(() => {
|
2024-02-26 19:53:44 +11:00
|
|
|
sceneInfra.camControls.setReactCameraPropertiesCallback(setCamSettings)
|
2024-02-14 08:03:20 +11:00
|
|
|
}, [sceneInfra])
|
|
|
|
useEffect(() => {
|
|
|
|
if (camSettings.type === 'perspective' && camSettings.fov) {
|
|
|
|
setFov(camSettings.fov)
|
|
|
|
}
|
|
|
|
}, [(camSettings as any)?.fov])
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<h3>cam settings</h3>
|
|
|
|
perspective cam
|
|
|
|
<input
|
|
|
|
type="checkbox"
|
|
|
|
checked={camSettings.type === 'perspective'}
|
|
|
|
onChange={(e) => {
|
|
|
|
if (camSettings.type === 'perspective') {
|
2024-02-26 19:53:44 +11:00
|
|
|
sceneInfra.camControls.useOrthographicCamera()
|
2024-02-14 08:03:20 +11:00
|
|
|
} else {
|
2024-02-26 19:53:44 +11:00
|
|
|
sceneInfra.camControls.usePerspectiveCamera()
|
2024-02-14 08:03:20 +11:00
|
|
|
}
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
{camSettings.type === 'perspective' && (
|
|
|
|
<input
|
|
|
|
type="range"
|
|
|
|
min="4"
|
|
|
|
max="90"
|
|
|
|
step={0.5}
|
|
|
|
value={fov}
|
|
|
|
onChange={(e) => {
|
|
|
|
setFov(parseFloat(e.target.value))
|
|
|
|
|
|
|
|
throttled({
|
|
|
|
...camSettings,
|
|
|
|
fov: parseFloat(e.target.value),
|
|
|
|
})
|
|
|
|
}}
|
|
|
|
className="w-full cursor-pointer pointer-events-auto"
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{camSettings.type === 'perspective' && (
|
|
|
|
<div>
|
|
|
|
<span>fov</span>
|
|
|
|
<input
|
|
|
|
type="number"
|
|
|
|
value={camSettings.fov}
|
|
|
|
className="text-black w-16"
|
|
|
|
onChange={(e) => {
|
2024-02-26 19:53:44 +11:00
|
|
|
sceneInfra.camControls.setCam({
|
2024-02-14 08:03:20 +11:00
|
|
|
...camSettings,
|
|
|
|
fov: parseFloat(e.target.value),
|
|
|
|
})
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
{camSettings.type === 'orthographic' && (
|
|
|
|
<>
|
|
|
|
<div>
|
|
|
|
<span>fov</span>
|
|
|
|
<input
|
|
|
|
type="number"
|
|
|
|
value={camSettings.zoom}
|
|
|
|
className="text-black w-16"
|
|
|
|
onChange={(e) => {
|
2024-02-26 19:53:44 +11:00
|
|
|
sceneInfra.camControls.setCam({
|
2024-02-14 08:03:20 +11:00
|
|
|
...camSettings,
|
|
|
|
zoom: parseFloat(e.target.value),
|
|
|
|
})
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</>
|
|
|
|
)}
|
|
|
|
<div>
|
|
|
|
Position
|
|
|
|
<ul className="flex">
|
|
|
|
<li>
|
|
|
|
<span className="pl-2 pr-1">x:</span>
|
|
|
|
<input
|
|
|
|
type="number"
|
|
|
|
step={5}
|
|
|
|
data-testid="cam-x-position"
|
|
|
|
value={camSettings.position[0]}
|
|
|
|
className="text-black w-16"
|
|
|
|
onChange={(e) => {
|
2024-02-26 19:53:44 +11:00
|
|
|
sceneInfra.camControls.setCam({
|
2024-02-14 08:03:20 +11:00
|
|
|
...camSettings,
|
|
|
|
position: [
|
|
|
|
parseFloat(e.target.value),
|
|
|
|
camSettings.position[1],
|
|
|
|
camSettings.position[2],
|
|
|
|
],
|
|
|
|
})
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</li>
|
|
|
|
<li>
|
|
|
|
<span className="pl-2 pr-1">y:</span>
|
|
|
|
<input
|
|
|
|
type="number"
|
|
|
|
step={5}
|
|
|
|
data-testid="cam-y-position"
|
|
|
|
value={camSettings.position[1]}
|
|
|
|
className="text-black w-16"
|
|
|
|
onChange={(e) => {
|
2024-02-26 19:53:44 +11:00
|
|
|
sceneInfra.camControls.setCam({
|
2024-02-14 08:03:20 +11:00
|
|
|
...camSettings,
|
|
|
|
position: [
|
|
|
|
camSettings.position[0],
|
|
|
|
parseFloat(e.target.value),
|
|
|
|
camSettings.position[2],
|
|
|
|
],
|
|
|
|
})
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</li>
|
|
|
|
<li>
|
|
|
|
<span className="pl-2 pr-1">z:</span>
|
|
|
|
<input
|
|
|
|
type="number"
|
|
|
|
step={5}
|
|
|
|
data-testid="cam-z-position"
|
|
|
|
value={camSettings.position[2]}
|
|
|
|
className="text-black w-16"
|
|
|
|
onChange={(e) => {
|
2024-02-26 19:53:44 +11:00
|
|
|
sceneInfra.camControls.setCam({
|
2024-02-14 08:03:20 +11:00
|
|
|
...camSettings,
|
|
|
|
position: [
|
|
|
|
camSettings.position[0],
|
|
|
|
camSettings.position[1],
|
|
|
|
parseFloat(e.target.value),
|
|
|
|
],
|
|
|
|
})
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|