import { IdeContext } from 'src/components/IdeToolbarNew' import { useRef, useState, useEffect, useContext } from 'react' import { Canvas, extend, useFrame, useThree } from 'react-three-fiber' import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' extend({ OrbitControls }) let debounceTimeoutId function Controls({ onCameraChange }) { const controls = useRef() const { scene, camera, gl } = useThree() useEffect(() => { // init camera position camera.position.x = 16 camera.position.y = 12 camera.fov = 22.5 // matches default openscad fov // Order matters with Euler rotations // We want it to rotate around the z or vertical axis first then the x axis to match openscad // in Three.js Y is the vertical axis (Z for openscad) camera.rotation._order = 'YXZ' const getRotations = () => { const { x, y, z } = camera.rotation const rad2Deg = 180 / Math.PI const scadX = (x + Math.PI / 2) * rad2Deg const scadZ = y * rad2Deg const scadY = z * rad2Deg return [scadX, scadY, scadZ] } const getPositions = () => { const { x: scadX, y: scadZ, z: negScadY } = camera.position const scale = 10 const scadY = -negScadY return [scadX * scale, scadY * scale, scadZ * scale] } if (controls.current) { const dragCallback = () => { clearTimeout(debounceTimeoutId) debounceTimeoutId = setTimeout(() => { const [rx, ry, rz] = getRotations() const [x, y, z] = getPositions() onCameraChange({ position: { x, y, z }, rotation: { x: rx, y: ry, z: rz }, }) }, 400) } const dragStart = () => clearTimeout(debounceTimeoutId) controls.current.addEventListener('end', dragCallback) controls.current.addEventListener('start', dragStart) const oldCurrent = controls.current dragCallback() return () => { oldCurrent.removeEventListener('end', dragCallback) oldCurrent.removeEventListener('start', dragStart) } } }, []) useFrame(() => controls.current.update()) return ( ) } function Box(props) { // This reference will give us direct access to the mesh const mesh = useRef() return ( ) } let currentCode // I have no idea why this works and using state.code is the dispatch doesn't but it was always stale const IdeViewer = () => { const { state, dispatch } = useContext(IdeContext) const [isDragging, setIsDragging] = useState(false) const [image, setImage] = useState() useEffect(() => { setImage( state.objectData?.type === 'png' && state.objectData?.data && window.URL.createObjectURL(state.objectData?.data) ) setIsDragging(false) }, [state.objectData]) currentCode = state.code return (
{state.isLoading && (
)} {image && (
)}
setIsDragging(true)} > { dispatch({ type: 'render', payload: { code: currentCode, camera: { position, rotation, }, }, }) }} />
) } export default IdeViewer