UNPKG

babylonjs-hook

Version:
252 lines (242 loc) 11.2 kB
import React, { createContext, useContext, useRef, useState, useEffect } from 'react'; import { Engine } from '@babylonjs/core/Engines/engine.js'; import { Scene } from '@babylonjs/core/scene.js'; /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __rest(s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; } var SceneContext = createContext({ scene: null, sceneReady: false }); /** * Get the scene from the context. */ var useScene = function () { return useContext(SceneContext).scene; }; var EngineCanvasContext = createContext({ engine: null, canvas: null }); function withEngineCanvasContext(Component) { return function BoundComponent(props) { return (React.createElement(EngineCanvasContext.Consumer, null, function (ctx) { return React.createElement(Component, __assign({}, props, { engineCanvasContext: ctx })); })); }; } /** * Get the engine from the context. */ var useEngine = function () { return useContext(EngineCanvasContext).engine; }; /** * Get the canvas DOM element from the context. */ var useCanvas = function () { return useContext(EngineCanvasContext).canvas; }; /** * Register a callback for before the scene renders. * * @param callback called using onBeforeRender functionality of scene * @param mask the mask used to filter observers * @param insertFirst if true will be inserted at first position, if false (default) will be last position. * @param callOnce only call the callback once */ var useBeforeRender = function (callback, mask, insertFirst, callOnce) { var scene = useContext(SceneContext).scene; useEffect(function () { if (scene === null) { return; } var unregisterOnFirstCall = callOnce === true; var sceneObserver = scene.onBeforeRenderObservable.add(callback, mask, insertFirst, undefined, unregisterOnFirstCall); if (unregisterOnFirstCall !== true) { return function () { scene.onBeforeRenderObservable.remove(sceneObserver); }; } }); }; /** * Register a callback for after the scene renders. * * @param callback called using onBeforeRender functionality of scene * @param mask the mask used to filter observers * @param insertFirst if true will be inserted at first position, if false (default) will be last position. * @param callOnce only call the callback once */ var useAfterRender = function (callback, mask, insertFirst, callOnce) { var scene = useContext(SceneContext).scene; useEffect(function () { if (scene === null) { return; } var unregisterOnFirstCall = callOnce === true; var sceneObserver = scene.onAfterRenderObservable.add(callback, mask, insertFirst, undefined, unregisterOnFirstCall); if (unregisterOnFirstCall !== true) { return function () { scene.onAfterRenderObservable.remove(sceneObserver); }; } }); }; /** * Handles creating a camera and attaching/disposing. * TODO: add new 4.2 parameters: useCtrlForPanning & panningMouseButton * @param createCameraFn function that creates and returns a camera * @param autoAttach Attach the input controls (default true) * @param noPreventDefault Events caught by controls should call prevent default * @param useCtrlForPanning (ArcRotateCamera only) * @param panningMoustButton (ArcRotateCamera only) */ var useCamera = function (createCameraFn, autoAttach, noPreventDefault /*, useCtrlForPanning: boolean = false, panningMouseButton: number*/) { if (autoAttach === void 0) { autoAttach = true; } if (noPreventDefault === void 0) { noPreventDefault = true; } var scene = useContext(SceneContext).scene; var cameraRef = useRef(null); useEffect(function () { if (scene === null) { console.warn('cannot create camera (scene not ready)'); return; } var camera = createCameraFn(scene); if (autoAttach === true) { var canvas = scene.getEngine().getRenderingCanvas(); // This attaches the camera to the canvas - adding extra parameters breaks backwards compatibility // https://github.com/BabylonJS/Babylon.js/pull/9192 (keep canvas to work with < 4.2 beta-13) // TODO: look at parameters of other camera types for attaching - likely need an 'options' parameter instead. // if (camera instanceof ArcRotateCamera) { // camera.attachControl(noPreventDefault, useCtrlForPanning, panningMouseButton) camera.attachControl(canvas, noPreventDefault); } cameraRef.current = camera; return function () { if (autoAttach === true) { // canvas is only needed for < 4.1 var canvas = scene.getEngine().getRenderingCanvas(); camera.detachControl(canvas); } camera.dispose(); }; }, [scene]); return cameraRef.current; }; var babylonjsHook = (function (props) { var reactCanvas = useRef(null); var antialias = props.antialias, engineOptions = props.engineOptions, adaptToDeviceRatio = props.adaptToDeviceRatio, sceneOptions = props.sceneOptions, onRender = props.onRender; props.onSceneReady; var renderChildrenWhenReady = props.renderChildrenWhenReady, children = props.children, rest = __rest(props, ["antialias", "engineOptions", "adaptToDeviceRatio", "sceneOptions", "onRender", "onSceneReady", "renderChildrenWhenReady", "children"]); var _a = useState({ scene: null, sceneReady: false }), sceneContext = _a[0], setSceneContext = _a[1]; var _b = useState({ engine: null, canvas: null }), engineContext = _b[0], setEngineContext = _b[1]; useEffect(function () { if (reactCanvas.current) { var engine_1 = new Engine(reactCanvas.current, antialias, engineOptions, adaptToDeviceRatio); setEngineContext(function () { return ({ engine: engine_1, canvas: reactCanvas.current }); }); var resizeObserver_1 = null; var scene_1 = new Scene(engine_1, sceneOptions); if (props.observeCanvasResize !== false && window.ResizeObserver) { resizeObserver_1 = new ResizeObserver(function () { engine_1.resize(); if (scene_1.activeCamera /* needed for rendering */) { // render to prevent flickering on resize if (typeof onRender === 'function') { onRender(scene_1); } scene_1.render(); } }); resizeObserver_1.observe(reactCanvas.current); } var sceneIsReady_1 = scene_1.isReady(); if (sceneIsReady_1) { props.onSceneReady(scene_1); } else { scene_1.onReadyObservable.addOnce(function (scene) { props.onSceneReady(scene); setSceneContext(function () { return ({ canvas: reactCanvas.current, scene: scene, engine: engine_1, sceneReady: true, }); }); }); } engine_1.runRenderLoop(function () { if (scene_1.activeCamera) { if (typeof onRender === 'function') { onRender(scene_1); } scene_1.render(); } else { // @babylonjs/core throws an error if you attempt to render with no active camera. // if we attach as a child React component we have frames with no active camera. console.warn('no active camera..'); } }); var resize_1 = function () { scene_1.getEngine().resize(); }; if (window) { window.addEventListener('resize', resize_1); } setSceneContext(function () { return ({ canvas: reactCanvas.current, scene: scene_1, engine: engine_1, sceneReady: sceneIsReady_1, }); }); return function () { // cleanup if (resizeObserver_1 !== null) { resizeObserver_1.disconnect(); } if (window) { window.removeEventListener('resize', resize_1); } scene_1.getEngine().dispose(); }; } }, [reactCanvas]); return (React.createElement(React.Fragment, null, React.createElement("canvas", __assign({ ref: reactCanvas }, rest)), React.createElement(EngineCanvasContext.Provider, { value: engineContext }, React.createElement(SceneContext.Provider, { value: sceneContext }, (renderChildrenWhenReady !== true || (renderChildrenWhenReady === true && sceneContext.sceneReady)) && children)))); }); export default babylonjsHook; export { EngineCanvasContext, SceneContext, useAfterRender, useBeforeRender, useCamera, useCanvas, useEngine, useScene, withEngineCanvasContext }; //# sourceMappingURL=babylonjs-hook.es5.js.map