import { PointerEventTypes , PointerInfo } from '@babylonjs/core/Events/pointerEvents.js' ; import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh.js' ; import { Observer } from '@babylonjs/core/Misc/observable.js' ; import '@babylonjs/core/Physics/physicsEngineComponent.js' ; import { Scene as BabylonScene , SceneOptions } from '@babylonjs/core/scene.js' ; import { Nullable } from '@babylonjs/core/types.js' ; import React , { MutableRefObject , useContext , useEffect , useRef , useState } from 'react' ; import { CreatedInstance } from './CreatedInstance' ; import { FiberScenePropsHandler } from './generatedCode' ; import { FiberSceneProps } from './generatedProps' ; import { EngineCanvasContext , EngineCanvasContextType , withEngineCanvasContext , } from './hooks/engine' ; import { SceneContext } from './hooks/scene' ; import { UpdatePayload } from './PropsHandler' ; import { Container } from './ReactBabylonJSHostConfig' ; import { createReconciler , ReconcilerInstance } from './render' ; import { applyUpdateToInstance } from './UpdateInstance' ; export declare type SceneEventArgs = { scene : BabylonScene ; canvas : HTMLCanvasElement ; } ; type SceneProps = { engineCanvasContext : EngineCanvasContextType ; onMeshPicked ? : ( mesh : AbstractMesh , scene : BabylonScene ) => void ; onScenePointerDown ? : ( evt : PointerInfo , scene : BabylonScene ) => void ; onScenePointerUp ? : ( evt : PointerInfo , scene : BabylonScene ) => void ; onScenePointerMove ? : ( evt : PointerInfo , scene : BabylonScene ) => void ; onSceneMount ? : ( sceneEventArgs : SceneEventArgs ) => void ; children : any ; sceneOptions ? : SceneOptions ; } & FiberSceneProps ; const updateScene = ( props , prevPropsRef , scene , propsHandler ) => { const prevProps = prevPropsRef . current ; const updates = propsHandler . getPropertyUpdates ( prevProps , props ) ; if ( updates !== null ) { updates . forEach ( ( propertyUpdate ) => { applyUpdateToInstance ( scene , propertyUpdate ) ; } ) ; } prevPropsRef . current = props ; } ; const Scene = ( props , context ? ) => { const { engine } = useContext ( EngineCanvasContext ) ; const [ propsHandler ] = useState ( new FiberScenePropsHandler ( ) ) ; const [ sceneReady , setSceneReady ] = useState ( false ) ; const [ scene , setScene ] = useState < Nullable < BabylonScene > > ( null ) ; const reconcilerRef = useRef < Nullable < ReconcilerInstance > > ( null ) ; const containerRef = useRef < Container | null > ( null ) ; const prevPropsRef = useRef < Partial < SceneProps > > ( { } ) ; useEffect ( ( ) => { const scene = new BabylonScene ( engine ! , props . sceneOptions ) ; const sceneIsReady = scene . isReady ( ) ; if ( sceneIsReady ) { setSceneReady ( true ) ; } else { console . error ( 'Scene is not ready. Report issue in react-babylonjs repo' ) ; } setScene ( scene ) ; const container = { scene : scene , rootInstance : { children : [ ] , customProps : { } , hostInstance : scene , metadata : { className : 'root' , } , observers : { } , parent : null , } , } ; updateScene ( props , prevPropsRef , container . rootInstance , propsHandler ) ; containerRef . current = container ; const reconciler = createReconciler ( { } ) ; reconcilerRef . current = reconciler ; const pointerDownObservable = scene . onPointerObservable . add ( ( evt ) => { if ( typeof props . onScenePointerDown === 'function' ) { props . onScenePointerDown ( evt , scene ) ; } if ( evt && evt . pickInfo && evt . pickInfo . hit && evt . pickInfo . pickedMesh ) { let mesh = evt . pickInfo . pickedMesh ; if ( typeof props . onMeshPicked === 'function' ) { props . onMeshPicked ( mesh , scene ) ; } else { } } } , PointerEventTypes . POINTERDOWN ) ; let pointerUpObservable = null ; if ( typeof props . onScenePointerUp === 'function' ) { pointerUpObservable = scene . onPointerObservable . add ( ( evt ) => { props . onScenePointerUp ! ( evt , scene ) ; } , PointerEventTypes . POINTERUP ) ; } let pointerMoveObservable = null ; if ( typeof props . onScenePointerMove === 'function' ) { pointerMoveObservable = scene . onPointerObservable . add ( ( evt ) => { props . onScenePointerMove ! ( evt , scene ) ; } , PointerEventTypes . POINTERMOVE ) ; } if ( typeof props . onSceneMount === 'function' ) { props . onSceneMount ( { scene : scene , canvas : scene . getEngine ( ) . getRenderingCanvas ( ) ! , } ) ; } if ( Array . isArray ( props . enablePhysics ) ) { scene . enablePhysics ( props . enablePhysics [ 0 ] , props . enablePhysics [ 1 ] ) ; } const sceneGraph = ( < SceneContext . Provider value = { { scene , sceneReady : sceneIsReady , } } > { props . children } < /SceneContext.Provider>); reconciler . render ( sceneGraph , container , ( ) => { } , null ) ; return ( ) => { if ( pointerDownObservable ) { scene . onPointerObservable . remove ( pointerDownObservable ) ; } if ( pointerUpObservable ) { scene . onPointerObservable . remove ( pointerUpObservable ) ; } if ( pointerMoveObservable ) { scene . onPointerObservable . remove ( pointerMoveObservable ) ; } if ( scene . isDisposed === false ) { scene . dispose ( ) ; } reconciler . render ( null , containerRef . current ! , ( ) => { } , null ) ; reconcilerRef . current = null ; containerRef . current = null ; } ; } , [ ] ) ; useEffect ( ( ) => { if ( engine === null || scene === null || reconcilerRef . current === null ) { return ; } updateScene ( props , prevPropsRef , containerRef . current ! . rootInstance , propsHandler ) ; const sceneGraph = ( < SceneContext . Provider value = { { scene , sceneReady , } } > { props . children } < /SceneContext.Provider>); reconcilerRef . current ! . render ( sceneGraph , containerRef . current ! , ( ) => { } , null ) ; } ) ; return null ; } ; export default withEngineCanvasContext ( Scene ) ;