import React from 'react' ; import PropTypes from 'prop-types' ; import { FiberRoot } from 'react-reconciler' ; import reglInit , { Cancellable , Vec4 , Regl , DefaultContext } from 'regl' ; import { vec4 } from 'gl-matrix' ; import ReglRenderer from '../renderer' ; import defregl , { DeferredRegl } from 'deferred-regl' ; import globalDeferredRegl from '../reactRegl' ; import Node from '../nodes/Node' ; interface ReglFrameProps { canvasRef ? : HTMLCanvasElement ; forwardedRef ? : ( ref : HTMLCanvasElement ) => void ; extensions ? : string [ ] ; optionalExtensions ? : string [ ] ; color ? : vec4 ; width ? : number ; height ? : number ; onLost ? : ( ) => void ; onRestore ? : ( ) => void ; depth ? : 1 | 0 ; onFrame ? : ( context : DefaultContext , regl : Regl ) => void ; webGLContext ? : WebGLContextAttributes ; } export class ReglFrame extends React . Component < ReglFrameProps , { } > { reglHandle ? : any ; tick ? : Cancellable ; canvasRef : HTMLCanvasElement | null = null ; fiberRoot ? : FiberRoot ; initQueue : any [ ] = [ ] ; legitRegl ? : Regl ; deferredRegl ? : DeferredRegl ; static childContextTypes = { reactify : PropTypes . bool , } ; getChildContext ( ) { return { reactify : true } ; } componentWillUnmount ( ) { if ( ! this . fiberRoot ) throw Error ( 'failed to unmount missing fiberRoot' ) ; ReglRenderer . updateContainer ( null , this . fiberRoot , this , ( ) => { globalDeferredRegl . setQueue ( this . initQueue . slice ( 0 ) ) ; if ( this . tick ) this . tick . cancel ( ) ; if ( this . legitRegl ) this . legitRegl . destroy ( ) ; globalDeferredRegl . setRegl ( ) ; } ) ; } componentDidMount ( ) { const canvasRef = this . props . canvasRef || this . canvasRef ; const webGLContextProps = this . props . webGLContext || { } ; let initProps = { } ; if ( canvasRef ) { const gl = canvasRef . getContext ( "webgl" , { alpha : false , antialias : false , stencil : false , preserveDrawingBuffer : false , ... webGLContextProps , } ) ; if ( ! gl ) throw new Error ( 'failed to aquire a gl context for regl' ) ; initProps . gl = gl ; } if ( this . props . extensions ) initProps . extensions = this . props . extensions ; if ( this . props . optionalExtensions ) initProps . optionalExtensions = this . props . optionalExtensions ; this . deferredRegl = defregl ( ) ; this . legitRegl = reglInit ( initProps ) ; if ( this . props . forwardedRef ) { this . props . forwardedRef . current = this . legitRegl . _gl . canvas ; } const node0 = new Node ( { id : 'react-regl-root' , regl : this . legitRegl } ) ; const fiberRoot = ReglRenderer . createContainer ( node0 , false , false ) ; this . fiberRoot = fiberRoot ; this . legitRegl . on ( 'lost' , ( ) => { console . error ( 'Regl WebGL context lost' ) ; if ( this . props . onLost ) this . props . onLost ( ) ; } ) ; this . legitRegl . on ( 'restore' , ( ) => { console . log ( 'Regl WebGL context restored' ) ; if ( this . props . onRestore ) this . props . onRestore ( ) ; } ) ; const color = this . props . color ? this . props . color as Vec4 : [ 0 , 0 , 0 , 1 ] ; this . legitRegl . clear ( { color , depth : this . props . depth || 1 } ) ; globalDeferredRegl . replicateTo ( this . deferredRegl ) ; this . deferredRegl . setRegl ( this . legitRegl ) ; ReglRenderer . updateContainer ( this . props . children , this . fiberRoot , this , ( ) => { fiberRoot . containerInfo . render ( ) ; } ) ; if ( this . props . onFrame && typeof this . props . onFrame === 'function' ) { this . tick = this . legitRegl . frame ( ( context ) => { if ( this . props . onFrame && this . legitRegl ) this . props . onFrame ( context , this . legitRegl ) ; if ( this . fiberRoot ) this . fiberRoot . containerInfo . render ( ) ; } ) ; } } componentDidUpdate ( prevProps , prevState ) { if ( prevProps . width !== this . props . width || prevProps . height !== this . props . height ) { if ( this . legitRegl ) { this . legitRegl . poll ( ) ; } } if ( typeof this . legitRegl !== 'undefined' && ( this . props . color || this . props . depth ) ) { this . legitRegl . clear ( { color : this . props . color as Vec4 , depth : this . props . depth || 1 } ) ; } if ( ! this . fiberRoot ) throw new Error ( "regl fiberRoot was undefined..." ) ; ReglRenderer . updateContainer ( this . props . children , this . fiberRoot , this , ( ) => { if ( ! this . fiberRoot ) throw new Error ( "regl fiberRoot was undefined on update..." ) ; this . fiberRoot . containerInfo . render ( ) ; } ) ; } render ( ) { if ( this . props . canvasRef || ( ! this . props . width && ! this . props . height ) ) { return null ; } return ( < canvas ref = { ( canvasRef ) => { if ( canvasRef ) { this . canvasRef = canvasRef ; if ( this . props . forwardedRef ) { this . props . forwardedRef ( canvasRef ) ; } } } } width = { this . props . width } height = { this . props . height } / > ) ; } }