import React, { createContext, FC, ReactNode, useContext, useState } from "react" import * as THREE from "three" import { AdaptiveToneMappingPass } from "three/examples/jsm/postprocessing/AdaptiveToneMappingPass.js" import T from "." import { Composer, Renderer, Ticker, useWindowResizeHandler } from "./engine" import { EffectPass, RenderPass, UnrealBloomPass, Vignette } from "./postprocessing" type RenderPipelineComponent = FC<{ scene: THREE.Scene camera: THREE.Camera children?: ReactNode }> export const BasicRenderPipeline: RenderPipelineComponent = ({ scene, camera, children }) => ( {children} ) export const FancyRenderPipeline: RenderPipelineComponent = ({ children, ...props }) => ( {children} ) function useNullableState(initial?: T | (() => T)) { return useState(initial!) } type ApplicationApi = { setScene: (scene: THREE.Scene | null) => void setCamera: (camera: THREE.Camera | null) => void } const ApplicationContext = createContext(null!) export const useApplication = () => useContext(ApplicationContext) export const Application: FC<{ children: ReactNode | ((api: ApplicationApi) => ReactNode) renderPipeline?: RenderPipelineComponent }> = ({ children, renderPipeline: RenderPipeline = BasicRenderPipeline }) => { const [scene, setScene] = useNullableState() const [camera, setCamera] = useNullableState() useWindowResizeHandler(() => { if (camera) { const width = window.innerWidth const height = window.innerHeight if (camera instanceof THREE.PerspectiveCamera) { camera.aspect = width / height camera.updateProjectionMatrix() } } }, [camera]) return ( {scene && camera && } {/* {scene && camera && } */} {children instanceof Function ? children({ setScene, setCamera }) : children} ) }