diff --git a/packages/playground/src/shared/r3f-rocket/App.tsx b/packages/playground/src/shared/r3f-rocket/App.tsx index 19feef1..eb9b650 100644 --- a/packages/playground/src/shared/r3f-rocket/App.tsx +++ b/packages/playground/src/shared/r3f-rocket/App.tsx @@ -53,7 +53,13 @@ function App() { height: '100vh', }} > - + diff --git a/packages/r3f/src/components/ReferenceWindow/ReferenceWindow.tsx b/packages/r3f/src/components/ReferenceWindow/ReferenceWindow.tsx new file mode 100644 index 0000000..fe11ebf --- /dev/null +++ b/packages/r3f/src/components/ReferenceWindow/ReferenceWindow.tsx @@ -0,0 +1,149 @@ +import type {VFC} from 'react' +import React, {useEffect, useLayoutEffect, useRef} from 'react' +import {useEditorStore} from '../../store' +import shallow from 'zustand/shallow' +import type {WebGLRenderer} from 'three' +import useMeasure from 'react-use-measure' +import styled, {keyframes} from 'styled-components' +import {TiWarningOutline} from 'react-icons/ti' +// This is ugly, but pure TS doesn't let you do bundler-stuff +import noiseImageUrl from './noiseImage' + +const Container = styled.div` + position: relative; + width: fit-content; + height: fit-content; + border-radius: 4px; + overflow: hidden; +` + +const Canvas = styled.canvas` + display: block; +` + +const staticAnimation = keyframes` + 0% { transform: translate(0,0) } + 10% { transform: translate(-5%,-5%) } + 20% { transform: translate(-10%,5%) } + 30% { transform: translate(5%,-10%) } + 40% { transform: translate(-5%,15%) } + 50% { transform: translate(-10%,5%) } + 60% { transform: translate(15%,0) } + 70% { transform: translate(0,10%) } + 80% { transform: translate(-15%,0) } + 90% { transform: translate(10%,5%) } + 100% { transform: translate(5%,0) } +` + +const Static = styled.div` + position: relative; + display: flex; + width: 200px; + height: 120px; + padding: 18px; + + ::before { + content: ''; + position: absolute; + z-index: -1; + top: -50%; + left: -50%; + right: -50%; + bottom: -50%; + background: #2f2f2f url(${noiseImageUrl}) repeat 0 0; + animation: ${staticAnimation} 0.2s infinite; + } +` + +const Warning = styled.div` + display: flex; + flex-direction: column; + gap: 12px; + align-items: center; + text-align: center; + opacity: 0.8; +` + +interface ReferenceWindowProps { + height: number +} + +const ReferenceWindow: VFC = ({height}) => { + const canvasRef = useRef(null) + + const [gl] = useEditorStore((state) => [state.gl], shallow) + const [ref, bounds] = useMeasure() + + const preserveDrawingBuffer = + ( + gl?.domElement.getContext('webgl') ?? gl?.domElement.getContext('webgl2') + )?.getContextAttributes()?.preserveDrawingBuffer ?? false + + useLayoutEffect(() => { + if (gl) { + ref(gl?.domElement) + } + }, [gl, ref]) + + useEffect(() => { + let animationHandle: number + const draw = (gl: WebGLRenderer) => () => { + animationHandle = requestAnimationFrame(draw(gl)) + + if (!gl.domElement || !preserveDrawingBuffer) { + cancelAnimationFrame(animationHandle) + return + } + + const width = (gl.domElement.width / gl.domElement.height) * height + + const ctx = canvasRef.current!.getContext('2d')! + + console.log(gl.domElement.getContext('webgl2')!.getContextAttributes()) + + // https://stackoverflow.com/questions/17861447/html5-canvas-drawimage-how-to-apply-antialiasing + ctx.imageSmoothingQuality = 'high' + + ctx.fillStyle = 'white' + ctx.fillRect(0, 0, width, height) + + ctx.drawImage(gl.domElement, 0, 0, width, height) + } + + if (gl) { + draw(gl)() + } + + return () => { + cancelAnimationFrame(animationHandle) + } + }, [gl, height, preserveDrawingBuffer]) + + return ( + + {gl?.domElement && preserveDrawingBuffer ? ( + + ) : ( + + + + + Please set
{`gl={{ preserveDrawingBuffer: true }}`}
on + the r3f Canvas for the reference window to work. +
+
+
+ )} +
+ ) +} + +export default ReferenceWindow diff --git a/packages/r3f/src/components/ReferenceWindow/noise-transparent.png b/packages/r3f/src/components/ReferenceWindow/noise-transparent.png new file mode 100644 index 0000000..45902c9 Binary files /dev/null and b/packages/r3f/src/components/ReferenceWindow/noise-transparent.png differ diff --git a/packages/r3f/src/components/ReferenceWindow/noiseImage.ts b/packages/r3f/src/components/ReferenceWindow/noiseImage.ts new file mode 100644 index 0000000..b4b6c3b --- /dev/null +++ b/packages/r3f/src/components/ReferenceWindow/noiseImage.ts @@ -0,0 +1,4 @@ +const imageDataUrl = + 'data:image/png;base64,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' + +export default imageDataUrl diff --git a/packages/r3f/src/components/SnapshotEditor.tsx b/packages/r3f/src/components/SnapshotEditor.tsx index 3a5b3ac..a3277d9 100644 --- a/packages/r3f/src/components/SnapshotEditor.tsx +++ b/packages/r3f/src/components/SnapshotEditor.tsx @@ -9,13 +9,15 @@ import ProxyManager from './ProxyManager' import studio, {ToolbarIconButton} from '@theatre/studio' import {useVal} from '@theatre/react' import styled, {createGlobalStyle, StyleSheetManager} from 'styled-components' -import {IoCameraReverseOutline} from 'react-icons/io5' import type {ISheet} from '@theatre/core' import useSnapshotEditorCamera from './useSnapshotEditorCamera' import {getEditorSheet, getEditorSheetObject} from './editorStuff' import type {$IntentionalAny} from '@theatre/shared/utils/types' import {InfiniteGridHelper} from '../InfiniteGridHelper' import {DragDetectorProvider} from './DragDetector' +import TooltipPortalProvider from './TooltipPortalProvider' +import {FiRefreshCw} from 'react-icons/fi' +import ReferenceWindow from './ReferenceWindow/ReferenceWindow' const GlobalStyle = createGlobalStyle` :host { @@ -97,16 +99,26 @@ const Overlay = styled.div` const Tools = styled.div` position: absolute; - left: 8px; - top: 6px; + left: 12px; + top: 12px; pointer-events: auto; ` +const ReferenceWindowContainer = styled.div` + position: absolute; + right: 12px; + top: 12px; + justify-content: center; +` + const SnapshotEditor: React.FC<{paneId: string}> = (props) => { const snapshotEditorSheet = getEditorSheet() const paneId = props.paneId const editorObject = getEditorSheetObject() + const showReferenceWindow = + useVal(editorObject?.props.viewport.showReferenceWindow) ?? true + const [sceneSnapshot, createSnapshot] = useEditorStore( (state) => [state.sceneSnapshot, state.createSnapshot], shallow, @@ -148,43 +160,49 @@ const SnapshotEditor: React.FC<{paneId: string}> = (props) => { <> - - - - - - - - - - {sceneSnapshot ? ( - <> - - { - gl.setClearColor('white') - }} - shadowMap - dpr={[1, 2]} - fog={'red'} - frameloop="demand" - onPointerMissed={onPointerMissed} + + + + + - - - - - ) : null} - - {/* */} + + + + {showReferenceWindow && ( + + + + )} + + + {sceneSnapshot ? ( + <> + + { + gl.setClearColor('white') + }} + shadowMap + dpr={[1, 2]} + fog={'red'} + frameloop="demand" + onPointerMissed={onPointerMissed} + > + + + + + ) : null} + + diff --git a/packages/r3f/src/components/TooltipPortalProvider.tsx b/packages/r3f/src/components/TooltipPortalProvider.tsx new file mode 100644 index 0000000..0955e50 --- /dev/null +++ b/packages/r3f/src/components/TooltipPortalProvider.tsx @@ -0,0 +1,27 @@ +import type {ReactNode} from 'react'; +import React, { useState} from 'react' +import {PortalContext} from 'reakit' +import styled from 'styled-components' + +const PortalHost = styled.div` + position: fixed; + inset: 0; + pointer-events: none; +` + +export interface PortalManagerProps { + children: ReactNode +} + +const TooltipPortalProvider: React.VFC = ({children}) => { + const [wrapper, setWrapper] = useState(null) + + return ( + + {children} + + + ) +} + +export default TooltipPortalProvider diff --git a/packages/r3f/src/components/editorStuff.ts b/packages/r3f/src/components/editorStuff.ts index a039679..9fb4155 100644 --- a/packages/r3f/src/components/editorStuff.ts +++ b/packages/r3f/src/components/editorStuff.ts @@ -22,6 +22,9 @@ const editorSheetObjectConfig = { }, {as: 'menu', label: 'Shading'}, ), + showReferenceWindow: types.boolean(true, { + label: 'Reference', + }), }, {label: 'Viewport Config'}, ),