import React , { useState , useMemo , useLayoutEffect , useRef } from 'react' ; import * as THREE from 'three' ; import { AUTO_UV2_OPT_OUT_FLAG } from './AutoUV2' ; import { ATLAS_OPT_OUT_FLAG } from './atlas' ; import { withLightScene , SCENE_OPT_OUT_FLAG } from './lightScene' ; import { initializeWorkbench , Workbench , WorkbenchSettings } from './workbench' ; import { runBakingPasses } from './bake' ; import WorkManager , { useWorkRequest } from './WorkManager' ; export const AutoUV2Ignore = ( { children } ) => { return ( < group name = "Auto-UV2 opt-out wrapper" userData = { { [ AUTO_UV2_OPT_OUT_FLAG ] : true } } > { children } < /group>); } ; export const LightmapIgnore = ( { children } ) => { return ( < group name = "Lightmap opt-out wrapper" userData = { { [ SCENE_OPT_OUT_FLAG ] : true , [ AUTO_UV2_OPT_OUT_FLAG ] : true , [ ATLAS_OPT_OUT_FLAG ] : true } } > { children } < /group>); } ; export const DebugContext = React . createContext < { atlasTexture : THREE . Texture ; outputTexture : THREE . Texture ; } | null > ( null ) ; async function runWorkflow ( scene , props , requestWork , onWorkbenchDebug ) { const workbench = await initializeWorkbench ( scene , props , requestWork ) ; onWorkbenchDebug ( workbench ) ; await withLightScene ( workbench , async ( ) => { await runBakingPasses ( workbench , requestWork ) ; } ) ; } const Suspender = ( { promise } ) => { throw promise ; } ; const LegacySuspenseFallbackIntercept = ( { onStarted } ) => { const onStartedRef = useRef ( onStarted ) ; onStartedRef . current = onStarted ; useLayoutEffect ( ( ) => { let onFinished = ( ) => { } ; const unmountPromise = new Promise < void > ( ( resolve ) => { onFinished = resolve ; } ) ; onStartedRef . current ( unmountPromise ) ; return ( ) => { onFinished ( ) ; } ; } , [ ] ) ; return null ; } ; const LightmapMain = ( props ) => { const propsRef = useRef ( props ) ; const isLegacyRef = useRef ( ! ! props . legacySuspense ) ; const requestWork = useWorkRequest ( ) ; const enabledRef = useRef ( ! props . disabled ) ; enabledRef . current = enabledRef . current || ! props . disabled ; const allowStart = enabledRef . current ; const [ workbench , setWorkbench ] = useState < Workbench | null > ( null ) ; const [ progress , setProgress ] = useState < { promise : Promise < void > ; isComplete : boolean ; } | null > ( null ) ; const legacySuspenseWaitPromiseRef = useRef < Promise < void > | null > ( null ) ; const sceneRef = useRef < unknown > ( ) ; useLayoutEffect ( ( ) => { if ( ! allowStart ) { return ; } const sceneReadyPromise = legacySuspenseWaitPromiseRef . current || Promise . resolve ( ) ; const promise = sceneReadyPromise . then ( ( ) => { const scene = sceneRef . current ; if ( ! scene || ! ( scene instanceof THREE . Scene ) ) { throw new Error ( 'expecting lightmap scene' ) ; } return runWorkflow ( scene , propsRef . current , requestWork , ( debugWorkbench ) => { setWorkbench ( debugWorkbench ) ; } ) ; } ) . then ( ( ) => { setProgress ( { promise , isComplete : true } ) ; } ) ; setProgress ( { promise , isComplete : false } ) ; } , [ allowStart , requestWork ] ) ; const debugInfo = useMemo ( ( ) => workbench ? { atlasTexture : workbench . atlasMap . texture , outputTexture : workbench . irradiance } : null , [ workbench ] ) ; const content = ( < group name = "Lightmap Scene Wrapper" > { React . cloneElement ( props . children , { ref : sceneRef } ) } < /group>); return ( < DebugContext . Provider value = { debugInfo } > { progress && ! progress . isComplete ? ( < Suspender promise = { progress . promise } / > ) : null } { isLegacyRef . current ? ( < React . Suspense fallback = { < LegacySuspenseFallbackIntercept onStarted = { ( promise ) => { legacySuspenseWaitPromiseRef . current = promise ; } } />}> { content } < /React.Suspense>) : (content)} < /DebugContext.Provider>); } ; export type LightmapProps = WorkbenchSettings & { disabled ? : boolean ; legacySuspense ? : boolean ; workPerFrame ? : number ; } ; const Lightmap = React . forwardRef < THREE . Scene , React . PropsWithChildren < LightmapProps > > ( ( { workPerFrame , children , ... props } , sceneRef ) => { return ( < WorkManager workPerFrame = { workPerFrame } > < LightmapMain { ... props } > < scene name = "Lightmap Scene" ref = { sceneRef } > { children } < /scene> < /LightmapMain> < /WorkManager>); } ) ; export default Lightmap ;