2023-08-08 18:30:26 -04:00
|
|
|
import {
|
|
|
|
MouseEventHandler,
|
|
|
|
WheelEventHandler,
|
|
|
|
useEffect,
|
|
|
|
useRef,
|
|
|
|
useState,
|
|
|
|
} from 'react'
|
2023-06-21 09:15:02 +10:00
|
|
|
import { v4 as uuidv4 } from 'uuid'
|
2023-06-22 16:43:33 +10:00
|
|
|
import { useStore } from '../useStore'
|
2023-08-08 18:30:26 -04:00
|
|
|
import { throttle } from '../lib/utils'
|
|
|
|
import { EngineCommand } from '../lang/std/engineConnection'
|
2023-03-06 20:13:34 +11:00
|
|
|
|
2023-08-06 21:29:26 -04:00
|
|
|
export const Stream = ({ className = '' }) => {
|
2023-08-08 18:30:26 -04:00
|
|
|
const [zoom, setZoom] = useState(0)
|
2023-03-06 20:13:34 +11:00
|
|
|
const videoRef = useRef<HTMLVideoElement>(null)
|
2023-08-06 21:29:26 -04:00
|
|
|
const {
|
|
|
|
mediaStream,
|
|
|
|
engineCommandManager,
|
|
|
|
setIsMouseDownInStream,
|
|
|
|
fileId,
|
|
|
|
setFileId,
|
|
|
|
setCmdId,
|
|
|
|
} = useStore((s) => ({
|
2023-06-22 16:43:33 +10:00
|
|
|
mediaStream: s.mediaStream,
|
|
|
|
engineCommandManager: s.engineCommandManager,
|
2023-08-06 21:29:26 -04:00
|
|
|
isMouseDownInStream: s.isMouseDownInStream,
|
|
|
|
setIsMouseDownInStream: s.setIsMouseDownInStream,
|
|
|
|
fileId: s.fileId,
|
|
|
|
setFileId: s.setFileId,
|
|
|
|
setCmdId: s.setCmdId,
|
2023-06-22 16:43:33 +10:00
|
|
|
}))
|
2023-03-06 20:13:34 +11:00
|
|
|
|
|
|
|
useEffect(() => {
|
2023-03-07 15:45:59 +11:00
|
|
|
if (
|
|
|
|
typeof window === 'undefined' ||
|
|
|
|
typeof RTCPeerConnection === 'undefined'
|
|
|
|
)
|
|
|
|
return
|
2023-06-22 16:43:33 +10:00
|
|
|
if (!videoRef.current) return
|
|
|
|
if (!mediaStream) return
|
|
|
|
videoRef.current.srcObject = mediaStream
|
2023-08-06 21:29:26 -04:00
|
|
|
setFileId(uuidv4())
|
2023-08-08 18:30:26 -04:00
|
|
|
setZoom(videoRef.current.getBoundingClientRect().height / 2)
|
2023-08-06 21:29:26 -04:00
|
|
|
}, [mediaStream, engineCommandManager, setFileId])
|
2023-03-06 20:13:34 +11:00
|
|
|
|
2023-06-22 16:43:33 +10:00
|
|
|
const handleMouseDown: MouseEventHandler<HTMLVideoElement> = ({
|
|
|
|
clientX,
|
|
|
|
clientY,
|
2023-07-20 14:08:32 -04:00
|
|
|
ctrlKey,
|
2023-06-22 16:43:33 +10:00
|
|
|
}) => {
|
|
|
|
if (!videoRef.current) return
|
|
|
|
const { left, top } = videoRef.current.getBoundingClientRect()
|
|
|
|
const x = clientX - left
|
|
|
|
const y = clientY - top
|
|
|
|
console.log('click', x, y)
|
|
|
|
|
|
|
|
const newId = uuidv4()
|
2023-08-06 21:29:26 -04:00
|
|
|
setCmdId(newId)
|
2023-06-22 16:43:33 +10:00
|
|
|
|
2023-07-20 14:08:32 -04:00
|
|
|
const interaction = ctrlKey ? 'pan' : 'rotate'
|
|
|
|
|
2023-06-22 16:43:33 +10:00
|
|
|
engineCommandManager?.sendSceneCommand({
|
2023-08-02 15:41:59 +10:00
|
|
|
type: 'modeling_cmd_req',
|
2023-06-22 16:43:33 +10:00
|
|
|
cmd: {
|
2023-08-02 15:41:59 +10:00
|
|
|
type: 'camera_drag_start',
|
|
|
|
interaction,
|
2023-08-03 07:28:06 +10:00
|
|
|
window: { x, y },
|
2023-06-22 16:43:33 +10:00
|
|
|
},
|
|
|
|
cmd_id: newId,
|
2023-08-06 21:29:26 -04:00
|
|
|
file_id: fileId,
|
2023-06-22 16:43:33 +10:00
|
|
|
})
|
2023-08-06 21:29:26 -04:00
|
|
|
|
|
|
|
setIsMouseDownInStream(true)
|
2023-06-22 16:43:33 +10:00
|
|
|
}
|
2023-08-06 21:29:26 -04:00
|
|
|
|
2023-08-08 18:30:26 -04:00
|
|
|
// TODO: consolidate this with the same function in App.tsx
|
|
|
|
const debounceSocketSend = throttle<EngineCommand>((message) => {
|
|
|
|
engineCommandManager?.sendSceneCommand(message)
|
|
|
|
}, 16)
|
|
|
|
|
|
|
|
const handleScroll: WheelEventHandler<HTMLVideoElement> = (e) => {
|
|
|
|
e.preventDefault()
|
|
|
|
debounceSocketSend({
|
|
|
|
type: 'modeling_cmd_req',
|
|
|
|
cmd: {
|
|
|
|
type: 'camera_drag_move',
|
|
|
|
interaction: 'zoom',
|
|
|
|
window: { x: 0, y: zoom + e.deltaY },
|
|
|
|
},
|
|
|
|
cmd_id: uuidv4(),
|
|
|
|
file_id: uuidv4(),
|
|
|
|
})
|
|
|
|
|
|
|
|
setZoom(zoom + e.deltaY)
|
|
|
|
}
|
|
|
|
|
2023-06-22 16:43:33 +10:00
|
|
|
const handleMouseUp: MouseEventHandler<HTMLVideoElement> = ({
|
|
|
|
clientX,
|
|
|
|
clientY,
|
2023-07-20 14:08:32 -04:00
|
|
|
ctrlKey,
|
2023-06-22 16:43:33 +10:00
|
|
|
}) => {
|
|
|
|
if (!videoRef.current) return
|
|
|
|
const { left, top } = videoRef.current.getBoundingClientRect()
|
|
|
|
const x = clientX - left
|
|
|
|
const y = clientY - top
|
|
|
|
|
2023-08-06 21:29:26 -04:00
|
|
|
const newCmdId = uuidv4()
|
|
|
|
setCmdId(newCmdId)
|
2023-06-21 09:15:02 +10:00
|
|
|
|
2023-07-20 14:08:32 -04:00
|
|
|
const interaction = ctrlKey ? 'pan' : 'rotate'
|
|
|
|
|
2023-06-22 16:43:33 +10:00
|
|
|
engineCommandManager?.sendSceneCommand({
|
2023-08-02 15:41:59 +10:00
|
|
|
type: 'modeling_cmd_req',
|
2023-06-22 16:43:33 +10:00
|
|
|
cmd: {
|
2023-08-02 15:41:59 +10:00
|
|
|
type: 'camera_drag_end',
|
|
|
|
interaction,
|
2023-08-03 07:28:06 +10:00
|
|
|
window: { x, y },
|
2023-06-22 16:43:33 +10:00
|
|
|
},
|
2023-08-06 21:29:26 -04:00
|
|
|
cmd_id: newCmdId,
|
|
|
|
file_id: fileId,
|
2023-06-22 16:43:33 +10:00
|
|
|
})
|
2023-08-06 21:29:26 -04:00
|
|
|
|
|
|
|
setCmdId('')
|
|
|
|
|
|
|
|
setIsMouseDownInStream(false)
|
2023-06-22 16:43:33 +10:00
|
|
|
}
|
2023-03-06 20:13:34 +11:00
|
|
|
|
|
|
|
return (
|
2023-08-06 21:29:26 -04:00
|
|
|
<div id="stream" className={className}>
|
2023-06-22 16:43:33 +10:00
|
|
|
<video
|
|
|
|
ref={videoRef}
|
|
|
|
muted
|
|
|
|
autoPlay
|
|
|
|
controls={false}
|
|
|
|
onMouseDown={handleMouseDown}
|
|
|
|
onMouseUp={handleMouseUp}
|
2023-07-20 14:08:32 -04:00
|
|
|
onContextMenu={(e) => e.preventDefault()}
|
|
|
|
onContextMenuCapture={(e) => e.preventDefault()}
|
2023-08-08 18:30:26 -04:00
|
|
|
onWheelCapture={handleScroll}
|
2023-08-06 21:29:26 -04:00
|
|
|
className="w-full h-full"
|
2023-06-22 16:43:33 +10:00
|
|
|
/>
|
2023-03-06 20:13:34 +11:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|