import * as React from 'react' ; import { WindowSizeSensor } from 'libreact/lib/WindowSizeSensor' ; import { ModelData , parseModel } from '../lib/modelDataParser' ; import { buildTexture } from '../lib/textureBuilder' ; import { prepareRenderData , createModelMeshes , createContainer } from '../lib/modelRenderer' ; import { createModelController , ModelController } from '../lib/modelController' ; import { createOrbitControls , createRenderer , createCamera , createLights , createClock , createScene } from '../lib/screneRenderer' ; const useAnimationFrame = function < T extends ( ... args : any [ ] ) => void > ( callback ) { const callbackRef = React . useRef ( callback ) ; React . useEffect ( ( ) => ( callbackRef . current = callback ) , [ callback ] ) ; const loop = ( ) => { ; ( frameRef as any ) . current = requestAnimationFrame ( loop ) ; callbackRef . current ( ) ; } ; const frameRef = React . useRef < number > ( null ) ; React . useLayoutEffect ( ( ) => { ; ( frameRef as any ) . current = requestAnimationFrame ( loop ) ; return ( ) => cancelAnimationFrame ( frameRef . current ! ) ; } , [ ] ) ; } ; type Props = { modelBuffer : ArrayBuffer ; setModelController : ( controller : ModelController ) => void ; setModelData : ( modelData : ModelData ) => void ; } ; export const Renderer = ( props ) => { const canvasRef = React . useRef < HTMLCanvasElement > ( null ) ; const camera = React . useMemo ( ( ) => createCamera ( ) , [ ] ) ; const clock = React . useMemo ( ( ) => createClock ( ) , [ ] ) ; const scene = React . useMemo ( ( ) => createScene ( ) , [ ] ) ; const renderer = React . useMemo ( ( ) => canvasRef . current && createRenderer ( canvasRef . current ) , [ canvasRef . current ] ) ; const orbitControls = React . useMemo ( ( ) => canvasRef . current && createOrbitControls ( camera , canvasRef . current ) , [ camera , canvasRef . current ] ) ; const lights = React . useMemo ( ( ) => createLights ( ) , [ ] ) ; const modelData = React . useMemo ( ( ) => parseModel ( props . modelBuffer ) , [ props . modelBuffer ] ) ; const meshesRenderData = React . useMemo ( ( ) => prepareRenderData ( modelData ) , [ modelData ] ) ; const textures = React . useMemo ( ( ) => modelData . textures . map ( texture => buildTexture ( props . modelBuffer , texture ) ) , [ modelData ] ) ; const meshes = React . useMemo ( ( ) => createModelMeshes ( meshesRenderData , modelData , textures ) , [ meshesRenderData , modelData , textures ] ) ; const controller = React . useMemo ( ( ) => createModelController ( meshes , meshesRenderData , modelData ) , [ meshes , meshesRenderData , modelData ] ) ; const container = React . useMemo ( ( ) => createContainer ( meshes ) , [ meshes ] ) ; React . useEffect ( ( ) => { if ( scene ) { scene . add ( container ) ; scene . add ( ... lights ) ; return ( ) => { scene . remove ( container ) ; scene . remove ( ... lights ) ; } ; } } , [ container , scene , lights ] ) ; React . useEffect ( ( ) => props . setModelData ( modelData ) , [ modelData ] ) ; React . useEffect ( ( ) => props . setModelController ( controller ) , [ controller ] ) ; useAnimationFrame ( ( ) => { if ( orbitControls ) { orbitControls . update ( ) ; } const delta = clock . getDelta ( ) ; controller . update ( delta ) ; if ( renderer ) { renderer . render ( scene , camera ) ; } } ) ; return ( < WindowSizeSensor onChange = { size => { camera . aspect = window . innerWidth / window . innerHeight ; camera . updateProjectionMatrix ( ) ; if ( renderer ) { renderer . setSize ( size . width , size . height ) ; } } } > { ( state ) => ( < canvas ref = { canvasRef } style = { { width : state . width + 'px' , height : state . height + 'px' } } />)} < /WindowSizeSensor>); } ;