Files
modeling-app/src/clientSideScene/ClientSideSceneComp.tsx

281 lines
8.1 KiB
TypeScript
Raw Normal View History

import { useRef, useEffect, useState } from 'react'
import { useModelingContext } from 'hooks/useModelingContext'
import { cameraMouseDragGuards } from 'lib/cameraControls'
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
import { useStore } from 'useStore'
import { ARROWHEAD, DEBUG_SHOW_BOTH_SCENES } from './sceneInfra'
import { ReactCameraProperties } from './CameraControls'
import { throttle } from 'lib/utils'
import { sceneInfra } from 'lib/singletons'
import {
EXTRA_SEGMENT_HANDLE,
PROFILE_START,
getParentGroup,
} from './sceneEntities'
function useShouldHideScene(): { hideClient: boolean; hideServer: boolean } {
const [isCamMoving, setIsCamMoving] = useState(false)
const [isTween, setIsTween] = useState(false)
const { state } = useModelingContext()
useEffect(() => {
sceneInfra.camControls.setIsCamMovingCallback((isMoving, isTween) => {
setIsCamMoving(isMoving)
setIsTween(isTween)
})
}, [])
if (DEBUG_SHOW_BOTH_SCENES || !isCamMoving)
return { hideClient: false, hideServer: false }
let hideServer = state.matches('Sketch')
if (isTween) {
hideServer = false
}
return { hideClient: !hideServer, hideServer }
}
export const ClientSideScene = ({
cameraControls,
}: {
cameraControls: ReturnType<
typeof useSettingsAuthContext
Rearchitect settings system to be scoped (#1956) * BROKEN: start of scopes for each setting * Clean up later: mostly-functional scoped settings! Broken command bar, unimplemented generated settings components * Working persisted project settings in-folder * Start working toward automatic commands and settings UI * Relatively stable, settings-menu-editable * Settings persistence tweaks after merge * Custom settings UI working properly, cleaner types * Allow boolean command types, create Settings UI for them * Add support for option and string Settings input types * Proof of concept settings from command bar * Add all settings to command bar * Allow settings to be hidden on a level * Better command titles for settings * Hide the settings the settings from the commands bar * Derive command defaultValue from *current* settingsMachine context * Fix generated settings UI for 'options' type settings * Pretty settings modal 💅 * Allow for rollback to parent level setting * fmt * Fix tsc errors not related to loading from localStorage * Better setting descriptions, better buttons * Make displayName searchable in command bar * Consolidate constants, get working in browser * Start fixing tests, better types for saved settings payloads * Fix playwright tests * Add a test for the settings modal * Add AtLeast to codespell ignore list * Goofed merge of codespellrc * Try fixing linux E2E tests * Make codespellrc word lowercase * fmt * Fix data-testid in Tauri test * Don't set text settings if nothing changed * Turn off unimplemented settings * Allow for multiple "execution-done" messages to have appeared in snapshot tests * Try fixing up snapshot tests * Switch from .json to .toml settings file format * Use a different method for overriding the default units * Try to force using the new common storage state in snapshot tests * Update tests to use TOML * fmt and remove console logs * Restore units to export * tsc errors, make snapshot tests use TOML * Ensure that snapshot tests use the basicStorageState * Re-organize use of test.use() * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Update snapshots one more time since lighting changed * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Fix broken "Show in folder" for project-level settings * Fire all relevant actions after settings reset * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * Properly reset the default directory * Hide settings by platform * Actually honor showDebugPanel * Unify settings hiding logic * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * fix first extrusion snapshot * another attempt to fix extrustion snapshot * Rerun test suite * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * trigger CI * more extrusion stuff * Replace resetSettings console log with comment --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Kurt Hutten Irev-Dev <k.hutten@protonmail.ch>
2024-04-02 10:29:34 -04:00
>['settings']['context']['modeling']['mouseControls']['current']
}) => {
const canvasRef = useRef<HTMLDivElement>(null)
const { state, send, context } = useModelingContext()
const { hideClient, hideServer } = useShouldHideScene()
const { setHighlightRange } = useStore((s) => ({
setHighlightRange: s.setHighlightRange,
highlightRange: s.highlightRange,
}))
// Listen for changes to the camera controls setting
// and update the client-side scene's controls accordingly.
useEffect(() => {
sceneInfra.camControls.interactionGuards =
cameraMouseDragGuards[cameraControls]
}, [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()
sceneInfra.setHighlightCallback(setHighlightRange)
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)
}
}, [])
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'
}
}
return (
<div
ref={canvasRef}
style={{ cursor: cursor }}
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) {
sceneInfra.camControls.dollyZoom(a.fov)
}
}, 1000 / 15)
export const CamDebugSettings = () => {
const [camSettings, setCamSettings] = useState<ReactCameraProperties>({
type: 'perspective',
fov: 12,
position: [0, 0, 0],
quaternion: [0, 0, 0, 1],
})
const [fov, setFov] = useState(12)
useEffect(() => {
sceneInfra.camControls.setReactCameraPropertiesCallback(setCamSettings)
}, [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') {
sceneInfra.camControls.useOrthographicCamera()
} else {
sceneInfra.camControls.usePerspectiveCamera()
}
}}
/>
{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) => {
sceneInfra.camControls.setCam({
...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) => {
sceneInfra.camControls.setCam({
...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) => {
sceneInfra.camControls.setCam({
...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) => {
sceneInfra.camControls.setCam({
...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) => {
sceneInfra.camControls.setCam({
...camSettings,
position: [
camSettings.position[0],
camSettings.position[1],
parseFloat(e.target.value),
],
})
}}
/>
</li>
</ul>
</div>
</div>
)
}