UNPKG

react-babylonjs-x

Version:
855 lines (853 loc) 792 kB
import { Vector3, Color3, Vector2, Color4 } from '@babylonjs/core/Maths/math'; import { VertexBuffer, VertexData, Mesh as Mesh$1, MeshBuilder } from '@babylonjs/core/Meshes'; import { Tools } from '@babylonjs/core/Misc/tools'; import { AbstractScene } from '@babylonjs/core/abstractScene'; import { Node as Node$1 } from '@babylonjs/core/node'; import { Scene as Scene$2 } from '@babylonjs/core/scene'; import { Camera as Camera$1 } from '@babylonjs/core/Cameras/camera'; import { EnvironmentHelper as EnvironmentHelper$1 } from '@babylonjs/core/Helpers/environmentHelper'; import { EffectLayer as EffectLayer$1 } from '@babylonjs/core/Layers/effectLayer'; import { Light as Light$1 } from '@babylonjs/core/Lights/light'; import { Material as Material$1 } from '@babylonjs/core/Materials/material'; import { Mesh as Mesh$2 } from '@babylonjs/core/Meshes/mesh'; import { MeshBuilder as MeshBuilder$1 } from '@babylonjs/core/Meshes/meshBuilder'; import { PhysicsImpostor as PhysicsImpostor$1 } from '@babylonjs/core/Physics/physicsImpostor'; import { AdvancedDynamicTexture as AdvancedDynamicTexture$1 } from '@babylonjs/gui/2D/advancedDynamicTexture'; import { GUI3DManager as GUI3DManager$1 } from '@babylonjs/gui/3D/gui3DManager'; import { AutoRotationBehavior as AutoRotationBehavior$1 } from '@babylonjs/core/Behaviors/Cameras/autoRotationBehavior'; import { BouncingBehavior as BouncingBehavior$1 } from '@babylonjs/core/Behaviors/Cameras/bouncingBehavior'; import { FramingBehavior as FramingBehavior$1 } from '@babylonjs/core/Behaviors/Cameras/framingBehavior'; import { AttachToBoxBehavior as AttachToBoxBehavior$1 } from '@babylonjs/core/Behaviors/Meshes/attachToBoxBehavior'; import { FadeInOutBehavior as FadeInOutBehavior$1 } from '@babylonjs/core/Behaviors/Meshes/fadeInOutBehavior'; import { MultiPointerScaleBehavior as MultiPointerScaleBehavior$1 } from '@babylonjs/core/Behaviors/Meshes/multiPointerScaleBehavior'; import { PointerDragBehavior as PointerDragBehavior$1 } from '@babylonjs/core/Behaviors/Meshes/pointerDragBehavior'; import { SixDofDragBehavior as SixDofDragBehavior$1 } from '@babylonjs/core/Behaviors/Meshes/sixDofDragBehavior'; import { VRExperienceHelper as VRExperienceHelper$1 } from '@babylonjs/core/Cameras/VR/vrExperienceHelper'; import { ShadowGenerator as ShadowGenerator$1 } from '@babylonjs/core/Lights/Shadows/shadowGenerator'; import { BaseTexture as BaseTexture$1 } from '@babylonjs/core/Materials/Textures/baseTexture'; import { Control as Control$1 } from '@babylonjs/gui/2D/controls/control'; import { TextBlock as TextBlock$1 } from '@babylonjs/gui/2D/controls/textBlock'; import { Control3D as Control3D$1 } from '@babylonjs/gui/3D/controls/control3D'; import { TransformNode as TransformNode$1 } from '@babylonjs/core/Meshes/transformNode'; import { AbstractMesh as AbstractMesh$1 } from '@babylonjs/core/Meshes/abstractMesh'; import { RenderTargetTexture as RenderTargetTexture$1 } from '@babylonjs/core/Materials/Textures/renderTargetTexture'; import { TargetCamera as TargetCamera$1 } from '@babylonjs/core/Cameras/targetCamera'; import { FreeCamera as FreeCamera$1 } from '@babylonjs/core/Cameras/freeCamera'; import { TouchCamera as TouchCamera$1 } from '@babylonjs/core/Cameras/touchCamera'; import { UniversalCamera as UniversalCamera$1 } from '@babylonjs/core/Cameras/universalCamera'; import { GamepadCamera as GamepadCamera$1 } from '@babylonjs/core/Cameras/gamepadCamera'; import { AnaglyphGamepadCamera as AnaglyphGamepadCamera$1 } from '@babylonjs/core/Cameras/Stereoscopic/anaglyphGamepadCamera'; import { StereoscopicGamepadCamera as StereoscopicGamepadCamera$1 } from '@babylonjs/core/Cameras/Stereoscopic/stereoscopicGamepadCamera'; import { AnaglyphUniversalCamera as AnaglyphUniversalCamera$1 } from '@babylonjs/core/Cameras/Stereoscopic/anaglyphUniversalCamera'; import { StereoscopicUniversalCamera as StereoscopicUniversalCamera$1 } from '@babylonjs/core/Cameras/Stereoscopic/stereoscopicUniversalCamera'; import { DeviceOrientationCamera as DeviceOrientationCamera$1 } from '@babylonjs/core/Cameras/deviceOrientationCamera'; import { VRDeviceOrientationFreeCamera as VRDeviceOrientationFreeCamera$1 } from '@babylonjs/core/Cameras/VR/vrDeviceOrientationFreeCamera'; import { VRDeviceOrientationGamepadCamera as VRDeviceOrientationGamepadCamera$1 } from '@babylonjs/core/Cameras/VR/vrDeviceOrientationGamepadCamera'; import { AnaglyphFreeCamera as AnaglyphFreeCamera$1 } from '@babylonjs/core/Cameras/Stereoscopic/anaglyphFreeCamera'; import { StereoscopicFreeCamera as StereoscopicFreeCamera$1 } from '@babylonjs/core/Cameras/Stereoscopic/stereoscopicFreeCamera'; import { VirtualJoysticksCamera as VirtualJoysticksCamera$1 } from '@babylonjs/core/Cameras/virtualJoysticksCamera'; import { WebVRFreeCamera as WebVRFreeCamera$1 } from '@babylonjs/core/Cameras/VR/webVRCamera'; import { WebXRCamera as WebXRCamera$1 } from '@babylonjs/core/XR/webXRCamera'; import { ArcRotateCamera as ArcRotateCamera$1 } from '@babylonjs/core/Cameras/arcRotateCamera'; import { AnaglyphArcRotateCamera as AnaglyphArcRotateCamera$1 } from '@babylonjs/core/Cameras/Stereoscopic/anaglyphArcRotateCamera'; import { StereoscopicArcRotateCamera as StereoscopicArcRotateCamera$1 } from '@babylonjs/core/Cameras/Stereoscopic/stereoscopicArcRotateCamera'; import { VRDeviceOrientationArcRotateCamera as VRDeviceOrientationArcRotateCamera$1 } from '@babylonjs/core/Cameras/VR/vrDeviceOrientationArcRotateCamera'; import { FlyCamera as FlyCamera$1 } from '@babylonjs/core/Cameras/flyCamera'; import { FollowCamera as FollowCamera$1, ArcFollowCamera as ArcFollowCamera$1 } from '@babylonjs/core/Cameras/followCamera'; import { ShaderMaterial as ShaderMaterial$1 } from '@babylonjs/core/Materials/shaderMaterial'; import { Texture as Texture$1 } from '@babylonjs/core/Materials/Textures/texture'; import { MultiMaterial as MultiMaterial$1 } from '@babylonjs/core/Materials/multiMaterial'; import { PushMaterial as PushMaterial$1 } from '@babylonjs/core/Materials/pushMaterial'; import { StandardMaterial as StandardMaterial$1 } from '@babylonjs/core/Materials/standardMaterial'; import { BackgroundMaterial as BackgroundMaterial$1 } from '@babylonjs/core/Materials/Background/backgroundMaterial'; import { ShadowLight as ShadowLight$1 } from '@babylonjs/core/Lights/shadowLight'; import { PBRBaseMaterial as PBRBaseMaterial$1 } from '@babylonjs/core/Materials/PBR/pbrBaseMaterial'; import { PBRBaseSimpleMaterial as PBRBaseSimpleMaterial$1 } from '@babylonjs/core/Materials/PBR/pbrBaseSimpleMaterial'; import { PBRMetallicRoughnessMaterial as PBRMetallicRoughnessMaterial$1 } from '@babylonjs/core/Materials/PBR/pbrMetallicRoughnessMaterial'; import { PBRSpecularGlossinessMaterial as PBRSpecularGlossinessMaterial$1 } from '@babylonjs/core/Materials/PBR/pbrSpecularGlossinessMaterial'; import { PBRMaterial as PBRMaterial$1 } from '@babylonjs/core/Materials/PBR/pbrMaterial'; import { NodeMaterial as NodeMaterial$1 } from '@babylonjs/core/Materials/Node/nodeMaterial'; import { FluentMaterial as FluentMaterial$1 } from '@babylonjs/gui/3D/materials/fluentMaterial'; import { DirectionalLight as DirectionalLight$1 } from '@babylonjs/core/Lights/directionalLight'; import { PointLight as PointLight$1 } from '@babylonjs/core/Lights/pointLight'; import { SpotLight as SpotLight$1 } from '@babylonjs/core/Lights/spotLight'; import { HemisphericLight as HemisphericLight$1 } from '@babylonjs/core/Lights/hemisphericLight'; import { Container as Container$1 } from '@babylonjs/gui/2D/controls/container'; import { Rectangle as Rectangle$1 } from '@babylonjs/gui/2D/controls/rectangle'; import { Button as Button$1 } from '@babylonjs/gui/2D/controls/button'; import { SelectionPanel as SelectionPanel$1 } from '@babylonjs/gui/2D/controls/selector'; import { ScrollViewer as ScrollViewer$1 } from '@babylonjs/gui/2D/controls/scrollViewers/scrollViewer'; import { Image as Image$1 } from '@babylonjs/gui/2D/controls/image'; import { StackPanel as StackPanel$1 } from '@babylonjs/gui/2D/controls/stackPanel'; import { VirtualKeyboard as VirtualKeyboard$1 } from '@babylonjs/gui/2D/controls/virtualKeyboard'; import { Ellipse as Ellipse$1 } from '@babylonjs/gui/2D/controls/ellipse'; import { Grid as Grid$1 } from '@babylonjs/gui/2D/controls/grid'; import { _ScrollViewerWindow as _ScrollViewerWindow$1 } from '@babylonjs/gui/2D/controls/scrollViewers/scrollViewerWindow'; import { Checkbox as Checkbox$1 } from '@babylonjs/gui/2D/controls/checkbox'; import { ColorPicker as ColorPicker$1 } from '@babylonjs/gui/2D/controls/colorpicker'; import { InputText as InputText$1 } from '@babylonjs/gui/2D/controls/inputText'; import { InputPassword as InputPassword$1 } from '@babylonjs/gui/2D/controls/inputPassword'; import { Line as Line$1 } from '@babylonjs/gui/2D/controls/line'; import { MultiLine as MultiLine$1 } from '@babylonjs/gui/2D/controls/multiLine'; import { RadioButton as RadioButton$1 } from '@babylonjs/gui/2D/controls/radioButton'; import { BaseSlider as BaseSlider$1 } from '@babylonjs/gui/2D/controls/sliders/baseSlider'; import { ScrollBar as ScrollBar$1 } from '@babylonjs/gui/2D/controls/sliders/scrollBar'; import { ImageScrollBar as ImageScrollBar$1 } from '@babylonjs/gui/2D/controls/sliders/imageScrollBar'; import { Slider as Slider$1 } from '@babylonjs/gui/2D/controls/sliders/slider'; import { ImageBasedSlider as ImageBasedSlider$1 } from '@babylonjs/gui/2D/controls/sliders/imageBasedSlider'; import { DisplayGrid as DisplayGrid$1 } from '@babylonjs/gui/2D/controls/displayGrid'; import { Container3D as Container3D$1 } from '@babylonjs/gui/3D/controls/container3D'; import { VolumeBasedPanel as VolumeBasedPanel$1 } from '@babylonjs/gui/3D/controls/volumeBasedPanel'; import { CylinderPanel as CylinderPanel$1 } from '@babylonjs/gui/3D/controls/cylinderPanel'; import { PlanePanel as PlanePanel$1 } from '@babylonjs/gui/3D/controls/planePanel'; import { ScatterPanel as ScatterPanel$1 } from '@babylonjs/gui/3D/controls/scatterPanel'; import { SpherePanel as SpherePanel$1 } from '@babylonjs/gui/3D/controls/spherePanel'; import { StackPanel3D as StackPanel3D$1 } from '@babylonjs/gui/3D/controls/stackPanel3D'; import { AbstractButton3D as AbstractButton3D$1 } from '@babylonjs/gui/3D/controls/abstractButton3D'; import { Button3D as Button3D$1 } from '@babylonjs/gui/3D/controls/button3D'; import { HolographicButton as HolographicButton$1 } from '@babylonjs/gui/3D/controls/holographicButton'; import { MeshButton3D as MeshButton3D$1 } from '@babylonjs/gui/3D/controls/meshButton3D'; import { GlowLayer as GlowLayer$1 } from '@babylonjs/core/Layers/glowLayer'; import { HighlightLayer as HighlightLayer$1 } from '@babylonjs/core/Layers/highlightLayer'; import { CubeTexture as CubeTexture$1 } from '@babylonjs/core/Materials/Textures/cubeTexture'; import { RawCubeTexture as RawCubeTexture$1 } from '@babylonjs/core/Materials/Textures/rawCubeTexture'; import { RawTexture as RawTexture$1 } from '@babylonjs/core/Materials/Textures/rawTexture'; import { ProceduralTexture as ProceduralTexture$1 } from '@babylonjs/core/Materials/Textures/Procedurals/proceduralTexture'; import { CustomProceduralTexture as CustomProceduralTexture$1 } from '@babylonjs/core/Materials/Textures/Procedurals/customProceduralTexture'; import { NoiseProceduralTexture as NoiseProceduralTexture$1 } from '@babylonjs/core/Materials/Textures/Procedurals/noiseProceduralTexture'; import { MirrorTexture as MirrorTexture$1 } from '@babylonjs/core/Materials/Textures/mirrorTexture'; import { MultiRenderTarget as MultiRenderTarget$1 } from '@babylonjs/core/Materials/Textures/multiRenderTarget'; import { RefractionTexture as RefractionTexture$1 } from '@babylonjs/core/Materials/Textures/refractionTexture'; import { MultiviewRenderTarget as MultiviewRenderTarget$1 } from '@babylonjs/core/Materials/Textures/MultiviewRenderTarget'; import { VideoTexture as VideoTexture$1 } from '@babylonjs/core/Materials/Textures/videoTexture'; import { DynamicTexture as DynamicTexture$1 } from '@babylonjs/core/Materials/Textures/dynamicTexture'; import { RawTexture3D as RawTexture3D$1 } from '@babylonjs/core/Materials/Textures/rawTexture3D'; import { RawTexture2DArray as RawTexture2DArray$1 } from '@babylonjs/core/Materials/Textures/rawTexture2DArray'; import { ColorGradingTexture as ColorGradingTexture$1 } from '@babylonjs/core/Materials/Textures/colorGradingTexture'; import { EquiRectangularCubeTexture as EquiRectangularCubeTexture$1 } from '@babylonjs/core/Materials/Textures/equiRectangularCubeTexture'; import { HDRCubeTexture as HDRCubeTexture$1 } from '@babylonjs/core/Materials/Textures/hdrCubeTexture'; import { HtmlElementTexture as HtmlElementTexture$1 } from '@babylonjs/core/Materials/Textures/htmlElementTexture'; import React, { createContext, useContext, useState, useRef, useEffect } from 'react'; import { Engine as Engine$1, Observable, StandardMaterial as StandardMaterial$2, Color3 as Color3$1, BoundingInfo, Vector3 as Vector3$1, SceneLoader, AbstractMesh as AbstractMesh$2, PhysicsImpostor as PhysicsImpostor$2, ShadowGenerator as ShadowGenerator$2, Scene as Scene$3, PointerEventTypes, ActionManager, ExecuteCodeAction } from '@babylonjs/core'; import ReactReconciler from 'react-reconciler'; import '@babylonjs/loaders'; import { Texture as Texture$2 } from '@babylonjs/core/Materials/Textures'; var CustomPropsHandler = /** @class */ (function () { function CustomPropsHandler() { } /** * Register a new props handler * * @param handler to register for props (a handler can only be registered once per ) * @returns a reference that can be used to unregister. */ CustomPropsHandler.RegisterPropsHandler = function (propsHandler) { var propsChangeType = propsHandler.propChangeType; if (!Array.isArray(CustomPropsHandler._registeredPropsHandlers[propsChangeType])) { CustomPropsHandler._registeredPropsHandlers[propsChangeType] = []; } var registeredHandlers = CustomPropsHandler._registeredPropsHandlers[propsChangeType]; var match = registeredHandlers.find(function (h) { return h === propsHandler; }); if (match !== undefined) { console.warn("Handler can only be registered once per type [" + propsChangeType + "]"); return match; } registeredHandlers.push(propsHandler); return propsHandler; }; /** * Unregister a props handler that was previously registered. * * @param propsHandler * * @returns if the props handler was found and unregistered */ CustomPropsHandler.UnregisterPropsHandler = function (propsHandlerToUnregister) { var propsChangeType = propsHandlerToUnregister.propChangeType; if (!Array.isArray(CustomPropsHandler._registeredPropsHandlers[propsChangeType])) { console.warn("cannot find " + propsHandlerToUnregister.name + " to unregister."); return false; } var registeredHandlers = CustomPropsHandler._registeredPropsHandlers[propsChangeType]; var index = registeredHandlers.indexOf(propsHandlerToUnregister); if (index === -1) { console.warn("cannot find " + propsHandlerToUnregister.name + " to unregister."); return false; } CustomPropsHandler._registeredPropsHandlers[propsChangeType] = registeredHandlers.slice(index, 1); return true; }; CustomPropsHandler.HandlePropsChange = function (propsChangeType, oldProp, newProp) { var registeredHandlers = CustomPropsHandler._registeredPropsHandlers[propsChangeType]; if (registeredHandlers === undefined) { return CustomPropsHandler.NOT_ACCEPTED; } var accepted = false; for (var _i = 0, registeredHandlers_1 = registeredHandlers; _i < registeredHandlers_1.length; _i++) { var handler = registeredHandlers_1[_i]; if (handler.accept(newProp)) { accepted = true; var propertyUpdatedProcessResult = handler.process(oldProp, newProp); // console.log(`handler '${handler.name}'custom prop processing result:`, oldProp, newProp, propertyUpdatedProcessResult); // give other custom handlers (if any) the opportunity to handle if (propertyUpdatedProcessResult.processed) { return { accepted: true, processed: true, value: propertyUpdatedProcessResult.value }; } } } return accepted ? CustomPropsHandler.ACCEPTED_NOT_PROCSSED : CustomPropsHandler.NOT_ACCEPTED; }; CustomPropsHandler._registeredPropsHandlers = {}; CustomPropsHandler.NOT_ACCEPTED = Object.freeze({ accepted: false, processed: false, value: null }); CustomPropsHandler.ACCEPTED_NOT_PROCSSED = Object.freeze({ accepted: true, processed: false, value: null }); return CustomPropsHandler; }()); var PropChangeType; (function (PropChangeType) { PropChangeType["Primitive"] = "Primitive"; PropChangeType["Vector3"] = "Vector3"; PropChangeType["Color3"] = "Color3"; PropChangeType["Color4"] = "Color4"; PropChangeType["Control"] = "Control"; PropChangeType["NumericArray"] = "NumericArray"; PropChangeType["Observable"] = "Observable"; PropChangeType["Method"] = "Method"; PropChangeType["LambdaExpression"] = "LambdaExpression"; PropChangeType["FresnelParameters"] = "FresnelParameters"; PropChangeType["Texture"] = "Texture"; })(PropChangeType || (PropChangeType = {})); /** * Encapsulates common error handling and handling of registered custom prop handlers. */ function propertyCheck(oldProp, newProp, propertyName, propertyType, propChangeType, changedProps, templateMethod) { try { var processedResult = CustomPropsHandler.HandlePropsChange(propChangeType, oldProp, newProp); if (processedResult.accepted) { if (processedResult.processed) { // console.log(`handled ${propChangeType} on ${propertyName} by custom handler - new Value: ${JSON.stringify(processedResult.value ?? {})}`); changedProps.push({ propertyName: propertyName, type: propertyType, changeType: propChangeType, value: processedResult.value }); } // we assume any custom handler that 'accepts' a property does not want to pass // down to built-in handler. ie: [] -> Vector3 would fail. return; } templateMethod(oldProp, newProp, changedProps); } catch (e) { console.error("Unable to update '" + propertyName + "' with " + propChangeType + ":", newProp); console.error(e); } } var checkVector3Diff = function (oldProp, newProp, propertyName, propertyType, changedProps) { propertyCheck(oldProp, newProp, propertyName, propertyType, PropChangeType.Vector3, changedProps, function (oldProp, newProp, changedProps) { if (newProp && (!oldProp || !newProp.equals(oldProp))) { changedProps.push({ propertyName: propertyName, type: propertyType, changeType: PropChangeType.Vector3, value: newProp }); } }); }; var checkColor3Diff = function (oldProp, newProp, propertyName, propertyType, changedProps) { propertyCheck(oldProp, newProp, propertyName, propertyType, PropChangeType.Color3, changedProps, function (oldProp, newProp, changedProps) { if (newProp && (!oldProp || !newProp.equals(oldProp))) { changedProps.push({ propertyName: propertyName, type: propertyType, changeType: PropChangeType.Color3, value: newProp }); } }); }; var checkColor4Diff = function (oldProp, newProp, propertyName, propertyType, changedProps) { propertyCheck(oldProp, newProp, propertyName, propertyType, PropChangeType.Color4, changedProps, function (oldProp, newProp, changedProps) { // Color4.equals() not added until PR #5517 if (newProp && (!oldProp || oldProp.r !== newProp.r || oldProp.g !== newProp.g || oldProp.b !== newProp.b || oldProp.a !== newProp.a)) { changedProps.push({ propertyName: propertyName, type: propertyType, changeType: PropChangeType.Color4, value: newProp }); } }); }; var checkFresnelParametersDiff = function (oldProp, newProp, propertyName, propertyType, changedProps) { propertyCheck(oldProp, newProp, propertyName, propertyType, PropChangeType.FresnelParameters, changedProps, function (oldProp, newProp, changedProps) { // FresnelParameters.equals() not added until PR #7818 (https://github.com/BabylonJS/Babylon.js/pull/7818) if (newProp /* won't clear the property value */ && (!oldProp || oldProp.bias !== newProp.bias || oldProp.power !== newProp.power || (!oldProp.leftColor || !oldProp.leftColor.equals(newProp.leftColor)) || (!oldProp.rightColor || !oldProp.rightColor.equals(newProp.rightColor)) || oldProp.isEnabled !== newProp.isEnabled)) { changedProps.push({ propertyName: propertyName, type: propertyType, changeType: PropChangeType.FresnelParameters, value: newProp }); } }); }; var checkLambdaDiff = function (oldProp, newProp, propertyName, propertyType, changedProps) { propertyCheck(oldProp, newProp, propertyName, propertyType, PropChangeType.LambdaExpression, changedProps, function (oldProp, newProp, changedProps) { if (newProp !== oldProp) { changedProps.push({ propertyName: propertyName, type: propertyType, changeType: PropChangeType.LambdaExpression, value: newProp }); } }); }; var checkControlDiff = function (oldProp, newProp, propertyName, propertyType, changedProps) { propertyCheck(oldProp, newProp, propertyName, propertyType, PropChangeType.Control, changedProps, function (oldProp, newProp, changedProps) { // only sets once if (newProp && !oldProp) { changedProps.push({ propertyName: propertyName, type: propertyType, changeType: PropChangeType.Control, value: newProp }); } }); }; var checkPrimitiveDiff = function (oldProp, newProp, propertyName, propertyType, changedProps) { propertyCheck(oldProp, newProp, propertyName, propertyType, PropChangeType.Primitive, changedProps, function (oldProp, newProp, changedProps) { if (newProp !== oldProp) { changedProps.push({ propertyName: propertyName, type: propertyType, changeType: PropChangeType.Primitive, value: newProp }); } }); }; var checkTextureDiff = function (oldProp, newProp, propertyName, propertyType, changedProps) { propertyCheck(oldProp, newProp, propertyName, propertyType, PropChangeType.Texture, changedProps, function (oldProp, newProp, changedProps) { if (newProp !== oldProp) { console.log('pushing texture:', propertyName, propertyType); changedProps.push({ propertyName: propertyName, type: propertyType, changeType: PropChangeType.Texture, value: newProp }); } }); }; var checkNumericArrayDiff = function (oldProp, newProp, propertyName, propertyType, changedProps) { propertyCheck(oldProp, newProp, propertyName, propertyType, PropChangeType.NumericArray, changedProps, function (oldProp, newProp, changedProps) { // just length - missing loop + indexOf comparison (or deepEquals()) if (newProp && (!oldProp || oldProp.length !== newProp.length)) { changedProps.push({ propertyName: propertyName, type: propertyType, changeType: PropChangeType.NumericArray, value: newProp }); } }); }; var checkObservableDiff = function (oldProp, newProp, propertyName, propertyType, changedProps) { propertyCheck(oldProp, newProp, propertyName, propertyType, PropChangeType.Observable, changedProps, function (oldProp, newProp, changedProps) { // if it starts with 'on' then we have different handling. if (oldProp === undefined && oldProp !== newProp) { changedProps.push({ propertyName: propertyName, type: propertyType, changeType: PropChangeType.Observable, value: newProp }); } }); }; /** * This method differs from the rest in that we need to pass in a list of arguments. Can be done by using: * 1. an array to signify each parameter (or Object.values(...)). * * @param oldProp value of method (array, object, primitive, etc.) * @param newProp value of method (array, object, primitive, etc.) * @param propertyName name of property for diff * @param propertyType signature of method (as string) * @param changedProps list to append to when a diff is found */ var checkMethodDiff = function (oldProp, newProp, propertyName, propertyType, changedProps) { if (oldProp !== newProp) { changedProps.push({ propertyName: propertyName, type: propertyType, changeType: PropChangeType.Method, value: newProp }); } }; // module Extensions { var DynamicTerrain = /** @class */ (function () { /** * constructor * @param name * @param options * @param scene * @param {*} mapData the array of the map 3D data : x, y, z successive float values * @param {*} mapSubX the data map number of x subdivisions : integer * @param {*} mapSubZ the data map number of z subdivisions : integer * @param {*} terrainSub the wanted terrain number of subdivisions : integer, multiple of 2. * @param {*} mapUVs the array of the map UV data (optional) : u,v successive values, each between 0 and 1. * @param {*} mapColors the array of the map Color data (optional) : x, y, z successive float values. * @param {*} mapNormals the array of the map normal data (optional) : r,g,b successive values, each between 0 and 1. * @param {*} invertSide boolean, to invert the terrain mesh upside down. Default false. * @param {*} camera the camera to link the terrain to. Optional, by default the scene active camera * @param {*} SPmapData an array of arrays or Float32Arrays (one per particle type) of object data (position, rotation, scaling) on the map. Optional. * @param {*} sps the Solid Particle System used to manage the particles. Required when used with SPmapData. * @param {*} SPcolorData an array of arrays or Float32Arrays (one per particle type) of object colors on the map. One series of r, g, b, a floats per object. Optional, requires a SPmapData and a sps to be passed. * @param {*} SPuvData an array of arrays or Float32Arrays (one per particle type) of object uvs on the map. One series of x, y, z, w floats per object. Optional, requires a SPmapData and a sps to be passed. */ function DynamicTerrain(name, scene, options) { var _this = this; this._particleDataStride = 9; // data stride : position, rotation, scaling : 9 floats this._particleColorStride = 4; // color stride : color4 : r, g, b, a : 4 floats this._particleUVStride = 4; // uv stride : vector4 : x, y, z, w : 4 floats this._subToleranceX = 1 | 0; // hoSPcw many cells flought over thy the camera on the terrain x axis before update this._subToleranceZ = 1 | 0; // hoSPcw many cells flought over thy the camera on the terrain z axis before update this._LODLimits = []; // arSPcray of LOD limits this._initialLOD = 1 | 0; // inSPcitial LOD value (integer > 0) this._LODValue = 1 | 0; // cuSPcrrent LOD value : initial + camera correction this._cameraLODCorrection = 0 | 0; // LOSPcD correction (integer) according to the camera altitude this._LODPositiveX = true; // DoeSPcs LOD apply to the terrain right edge ? this._LODNegativeX = true; // DoeSPcs LOD apply to the terrain left edge ? this._LODPositiveZ = true; // DoeSPcs LOD apply to the terrain upper edge ? this._LODNegativeZ = true; // DoeSPcs LOD apply to the terrain lower edge ? this._inverted = false; // is the terrain mesh inverted upside down ? this.shiftFromCamera = { // terrain center shift from camera position x: 0.0, z: 0.0 }; this._deltaSubX = 0 | 0; // map x subdivision delta : variation in number of map subdivisions this._deltaSubZ = 0 | 0; // map z subdivision delta this._refreshEveryFrame = false; // boolean : to force the terrain computation every frame this._useCustomVertexFunction = false; // boolean : to allow the call to updateVertex() this._computeNormals = false; // boolean : to skip or not the normal computation this._datamap = false; // boolean : true if an data map is passed as parameter this._uvmap = false; // boolean : true if an UV map is passed as parameter this._colormap = false; // boolean : true if an color map is passed as parameter this._mapSPData = false; // boolean : true if a SPmapData array is passed as parameter this._colorSPData = false; // boolean : true if a SPcolorData array is passed as parameter this._uvSPData = false; // boolean : true if a SPuvData array is passed as parameter this._averageSubSizeX = 0.0; // map cell average x size this._averageSubSizeZ = 0.0; // map cell average z size this._terrainSizeX = 0.0; // terrain x size this._terrainSizeZ = 0.0; // terrain y size this._terrainHalfSizeX = 0.0; this._terrainHalfSizeZ = 0.0; this._centerWorld = Vector3.Zero(); // terrain world center position this._centerLocal = Vector3.Zero(); // terrain local center position this._mapSizeX = 0.0; // map x size this._mapSizeZ = 0.0; // map z size this._isAlwaysVisible = false; // is the terrain mesh always selected for rendering this._precomputeNormalsFromMap = false; // if the normals must be precomputed from the map data when assigning a new map to the existing terrain this.name = name; options = options || {}; this._terrainSub = options.terrainSub || 60; this._mapData = options.mapData; this._terrainIdx = this._terrainSub + 1; this._mapSubX = options.mapSubX || this._terrainIdx; this._mapSubZ = options.mapSubZ || this._terrainIdx; this._mapUVs = options.mapUVs; // if not defined, it will be still populated by default values this._mapColors = options.mapColors; this._scene = scene; this._terrainCamera = options.camera || scene.activeCamera; this._inverted = options.invertSide; this._SPmapData = options.SPmapData; this._SPcolorData = options.SPcolorData; this._SPuvData = options.SPuvData; this._sps = options.sps; // initialize the map arrays if not passed as parameters this._datamap = this._mapData ? true : false; this._uvmap = this._mapUVs ? true : false; this._colormap = this._mapColors ? true : false; this._mapSPData = this._SPmapData ? true : false; this._colorSPData = this._mapSPData && this._SPcolorData ? true : false; this._uvSPData = this._mapSPData && this._SPuvData ? true : false; this._mapData = this._datamap ? this._mapData : new Float32Array(this._terrainIdx * this._terrainIdx * 3); this._mapUVs = this._uvmap ? this._mapUVs : new Float32Array(this._terrainIdx * this._terrainIdx * 2); if (this._datamap) { this._mapNormals = options.mapNormals || new Float32Array(this._mapSubX * this._mapSubZ * 3); } else { this._mapNormals = new Float32Array(this._terrainIdx * this._terrainIdx * 3); } // Ribbon creation var index = 0; // current vertex index in the map array var posIndex = 0; // current position (coords) index in the map array var colIndex = 0; // current color index in the color array var uvIndex = 0; // current uv index in the uv array var color; // current color var uv; // current uv var terIndex = 0; // current index in the terrain array var y = 0.0; // current y coordinate var terrainPath; // current path var u = 0.0; // current u of UV var v = 0.0; // current v of UV var lg = this._terrainIdx + 1; // augmented length for the UV to finish before var terrainData = []; var terrainColor = []; var terrainUV = []; var mapData = this._mapData; var mapColors = this._mapColors; var mapUVs = this._mapUVs; for (var j = 0; j <= this._terrainSub; j++) { terrainPath = []; for (var i = 0; i <= this._terrainSub; i++) { index = this._mod(j * 3, this._mapSubZ) * this._mapSubX + this._mod(i * 3, this._mapSubX); posIndex = index * 3; colIndex = index * 3; uvIndex = index * 2; terIndex = j * this._terrainIdx + i; // geometry if (this._datamap) { y = mapData[posIndex + 1]; } else { y = 0.0; mapData[3 * terIndex] = i; mapData[3 * terIndex + 1] = y; mapData[3 * terIndex + 2] = j; } terrainPath.push(new Vector3(i, y, j)); // color if (this._colormap) { color = new Color4(mapColors[colIndex], mapColors[colIndex + 1], mapColors[colIndex + 2], 1.0); } else { color = new Color4(1.0, 1.0, 1.0, 1.0); } terrainColor.push(color); // uvs if (this._uvmap) { uv = new Vector2(mapUVs[uvIndex], mapUVs[uvIndex + 1]); } else { u = 1.0 - Math.abs(1.0 - (2.0 * i) / lg); v = 1.0 - Math.abs(1.0 - (2.0 * j) / lg); mapUVs[2 * terIndex] = u; mapUVs[2 * terIndex + 1] = v; uv = new Vector2(u, v); } terrainUV.push(uv); } terrainData.push(terrainPath); } this._mapSizeX = Math.abs(mapData[(this._mapSubX - 1) * 3] - mapData[0]); this._mapSizeZ = Math.abs(mapData[(this._mapSubZ - 1) * this._mapSubX * 3 + 2] - mapData[2]); this._averageSubSizeX = this._mapSizeX / this._mapSubX; this._averageSubSizeZ = this._mapSizeZ / this._mapSubZ; var ribbonOptions = { pathArray: terrainData, sideOrientation: options.invertSide ? Mesh$1.FRONTSIDE : Mesh$1.BACKSIDE, colors: terrainColor, uvs: terrainUV, updatable: true }; this._terrain = MeshBuilder.CreateRibbon("terrain", ribbonOptions, this._scene); this._indices = this._terrain.getIndices(); this._positions = this._terrain.getVerticesData(VertexBuffer.PositionKind); this._normals = this._terrain.getVerticesData(VertexBuffer.NormalKind); this._uvs = this._terrain.getVerticesData(VertexBuffer.UVKind); this._colors = this._terrain.getVerticesData(VertexBuffer.ColorKind); this.computeNormalsFromMap(); // update it immediatly and register the update callback function in the render loop this.update(true); this._terrain.position.x = this._terrainCamera.globalPosition.x - this._terrainHalfSizeX + this.shiftFromCamera.x; this._terrain.position.z = this._terrainCamera.globalPosition.z - this._terrainHalfSizeZ + this.shiftFromCamera.z; // initialize deltaSub to make on the map var deltaNbSubX = (this._terrain.position.x - mapData[0]) / this._averageSubSizeX; var deltaNbSubZ = (this._terrain.position.z - mapData[2]) / this._averageSubSizeZ; this._deltaSubX = deltaNbSubX > 0 ? Math.floor(deltaNbSubX) : Math.ceil(deltaNbSubX); this._deltaSubZ = deltaNbSubZ > 0 ? Math.floor(deltaNbSubZ) : Math.ceil(deltaNbSubZ); this._scene.onBeforeRenderObservable.add(function () { var refreshEveryFrame = _this._refreshEveryFrame; _this.beforeUpdate(refreshEveryFrame); _this.update(refreshEveryFrame); _this.afterUpdate(refreshEveryFrame); }); // if SP data, populate the map quads // mapQuads[mapIndex][partType] = [partIdx1 , partIdx2 ...] partIdx are particle indexes in SPmapData var SPmapData = this._SPmapData; var dataStride = this._particleDataStride; if (this._mapSPData) { var mapSizeX = this._mapSizeX; var mapSizeZ = this._mapSizeZ; var mapSubX = this._mapSubX; var mapSubZ = this._mapSubZ; var quads = []; this._mapQuads = quads; var x0 = mapData[0]; var z0 = mapData[2]; for (var t = 0; t < SPmapData.length; t++) { var data = SPmapData[t]; var nb = (data.length / dataStride) | 0; for (var pIdx = 0; pIdx < nb; pIdx++) { // particle position x, z in the map var dIdx = pIdx * dataStride; var x = data[dIdx]; var z = data[dIdx + 2]; x = x - Math.floor((x - x0) / mapSizeX) * mapSizeX; z = z - Math.floor((z - z0) / mapSizeZ) * mapSizeZ; var col = Math.floor(((x - x0) * mapSubX) / mapSizeX); var row = Math.floor(((z - z0) * mapSubZ) / mapSizeZ); var quadIdx = row * mapSubX + col; if (quads[quadIdx] === undefined) { quads[quadIdx] = []; } if (quads[quadIdx][t] === undefined) { quads[quadIdx][t] = []; } var quad = quads[quadIdx][t]; // push the particle index from the SPmapData array into the quads array quad.push(pIdx); } } // update the sps var sps = this._sps; sps.computeBoundingBox = true; sps.isAlwaysVisible = true; if (this._colorSPData) { sps.computeParticleColor = true; } if (this._uvSPData) { sps.computeParticleTexture = true; } // store particle types var spsTypeStartIndexes = []; this._spsTypeStartIndexes = spsTypeStartIndexes; var spsNbPerType = []; this._spsNbPerType = spsNbPerType; var nbAvailablePerType = []; this._nbAvailablePerType = nbAvailablePerType; var nbParticles = sps.nbParticles; var particles = sps.particles; var type = 0; spsTypeStartIndexes.push(type); nbAvailablePerType.push(0); var count = 1; for (var p = 1; p < nbParticles; p++) { particles[p].isVisible = false; if (type != particles[p].shapeId) { type++; spsTypeStartIndexes.push(p); spsNbPerType.push(count); nbAvailablePerType.push(count); count = 0; } count++; } spsNbPerType.push(count); } this.update(true); // recompute everything once the initial deltas are calculated } /** * Updates the terrain position and shape according to the camera position. * `force` : boolean, forces the terrain update even if no camera position change. * Returns the terrain. */ DynamicTerrain.prototype.update = function (force) { var needsUpdate = false; var updateLOD = false; var updateForced = force ? true : false; var terrainPosition = this._terrain.position; var cameraPosition = this._terrainCamera.globalPosition; var shiftFromCamera = this.shiftFromCamera; var terrainHalfSizeX = this._terrainHalfSizeX; var terrainHalfSizeZ = this._terrainHalfSizeZ; var deltaX = terrainHalfSizeX + terrainPosition.x - cameraPosition.x - shiftFromCamera.x; var deltaZ = terrainHalfSizeZ + terrainPosition.z - cameraPosition.z - shiftFromCamera.z; var subToleranceX = this._subToleranceX; var subToleranceZ = this._subToleranceZ; var mod = this._mod; // current LOD var oldCorrection = this._cameraLODCorrection; this._cameraLODCorrection = this.updateCameraLOD(this._terrainCamera) | 0; updateLOD = oldCorrection == this._cameraLODCorrection ? false : true; var LODValue = this._initialLOD + this._cameraLODCorrection; LODValue = LODValue > 0 ? LODValue : 1; this._LODValue = LODValue; // threshold sizes on each axis to trigger the terrain update var mapShiftX = this._averageSubSizeX * subToleranceX * LODValue; var mapShiftZ = this._averageSubSizeZ * subToleranceZ * LODValue; var mapFlgtNb = 0 | 0; // number of map cells flought over by the camera in the delta shift var deltaSubX = this._deltaSubX; var deltaSubZ = this._deltaSubZ; if (Math.abs(deltaX) > mapShiftX) { var signX = deltaX > 0.0 ? -1 : 1; mapFlgtNb = Math.abs(deltaX / mapShiftX) | 0; terrainPosition.x += mapShiftX * signX * mapFlgtNb; deltaSubX += subToleranceX * signX * LODValue * mapFlgtNb; needsUpdate = true; } if (Math.abs(deltaZ) > mapShiftZ) { var signZ = deltaZ > 0.0 ? -1 : 1; mapFlgtNb = Math.abs(deltaZ / mapShiftZ) | 0; terrainPosition.z += mapShiftZ * signZ * mapFlgtNb; deltaSubZ += subToleranceZ * signZ * LODValue * mapFlgtNb; needsUpdate = true; } var updateSize = updateLOD || updateForced; // must the terrain size be updated ? if (needsUpdate || updateSize) { this._deltaSubX = mod(deltaSubX, this._mapSubX); this._deltaSubZ = mod(deltaSubZ, this._mapSubZ); this._updateTerrain(updateSize); } terrainHalfSizeX = this._terrainHalfSizeX; terrainHalfSizeZ = this._terrainHalfSizeZ; this.centerLocal.copyFromFloats(terrainHalfSizeX, 0.0, terrainHalfSizeZ); this._centerWorld.copyFromFloats(terrainPosition.x + terrainHalfSizeX, terrainPosition.y, terrainPosition.z + terrainHalfSizeZ); return this; }; // private : updates the underlying ribbon DynamicTerrain.prototype._updateTerrain = function (updateSize) { var stepJ = 0 | 0; var stepI = 0 | 0; var LODLimitDown = 0 | 0; var LODLimitUp = 0 | 0; var LODValue = this._LODValue; // terrain LOD value var axisLODValue = LODValue; // current axis computed LOD value var lodI = LODValue; // LOD X var lodJ = LODValue; // LOD Z var bbMin = DynamicTerrain._bbMin; var bbMax = DynamicTerrain._bbMax; var terrain = this._terrain; var positions = this._positions; var normals = this._normals; var colors = this._colors; var uvs = this._uvs; var mapColors = this._mapColors; var mapNormals = this._mapNormals; var mapData = this._mapData; var mapUVs = this._mapUVs; var mapSPData = this._mapSPData; var quads = this._mapQuads; var nbPerType = this._spsNbPerType; var SPmapData = this._SPmapData; var SPcolorData = this._SPcolorData; var SPuvData = this._SPuvData; var dataStride = this._particleDataStride; var colorStride = this._particleColorStride; var uvStride = this._particleUVStride; var LODLimits = this._LODLimits; var terrainSub = this._terrainSub; var mod = this._mod; var terrainIdx = this._terrainIdx; var mapSubX = this._mapSubX; var mapSubZ = this._mapSubZ; var deltaSubX = this._deltaSubX; var deltaSubZ = this._deltaSubZ; var datamap = this._datamap; var uvmap = this._uvmap; var colormap = this._colormap; var useCustomVertexFunction = this._useCustomVertexFunction; var updateVertex = this.updateVertex; var dontComputeNormals = !this._computeNormals; var LODpstvX = this._LODPositiveX; var LODngtvX = this._LODNegativeX; var LODpstvZ = this._LODPositiveZ; var LODngtvZ = this._LODNegativeZ; var mapSizeX = this._mapSizeX; var mapSizeZ = this._mapSizeZ; var averageSubSizeX = this._averageSubSizeX; var averageSubSizeZ = this._averageSubSizeZ; var particleMap = mapSPData && quads; var particleColorMap = particleMap && this._colorSPData; var particleUVMap = particleMap && this._uvSPData; var l = 0 | 0; var index = 0 | 0; // current vertex index in the map data array var posIndex1 = 0 | 0; // current position index in the map data array var posIndex2 = 0 | 0; var posIndex3 = 0 | 0; var colIndex = 0 | 0; // current index in the map color array var uvIndex = 0 | 0; // current index in the map uv array var terIndex = 0 | 0; // current vertex index in the terrain map array when used as a data map var ribbonInd = 0 | 0; // current ribbon vertex index var ribbonPosInd = 0 | 0; // current ribbon position index (same than normal index) var ribbonUVInd = 0 | 0; // current ribbon UV index var ribbonColInd = 0 | 0; // current ribbon color index var ribbonColInd1 = 0 | 0; var ribbonColInd2 = 0 | 0; var ribbonColInd3 = 0 | 0; var ribbonColInd4 = 0 | 0; var ribbonPosInd1 = 0 | 0; var ribbonPosInd2 = 0 | 0; var ribbonPosInd3 = 0 | 0; // note : all the indexes are explicitly set as integers for the js optimizer (store them all in the stack) if (updateSize) { this.updateTerrainSize(); } Vector3.FromFloatsToRef(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, bbMin); Vector3.FromFloatsToRef(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE, bbMax); if (particleMap) { var sps = this._sps; var particles = sps.particles; var spsTypeStartIndexes = this._spsTypeStartIndexes; var nbAvailablePerType = this._nbAvailablePerType; var x0 = mapData[0]; var z0 = mapData[2]; var terrainPos = terrain.position; // reset all the particles to invisible var nbParticles = sps.nbParticles; for (var p = 0; p < nbParticles; p++) { particles[p].isVisible = false; } } for (var j = 0 | 0; j <= terrainSub; j++) { // LOD Z axisLODValue = LODValue; for (l = 0; l < LODLimits.length; l++) { LODLimitDown = LODLimits[l]; LODLimitUp = terrainSub - LODLimitDown - 1; if ((LODngtvZ && j < LODLimitDown) || (LODpstvZ && j > LODLimitUp)) { axisLODValue = l + 1 + LODValue; } lodJ = axisLODValue; } for (var i = 0 | 0; i <= terrainSub; i++) { // LOD X axisLODValue = LODValue; for (l = 0; l < LODLimits.length; l++) { LODLimitDown = LODLimits[l]; LODLimitUp = terrainSub - LODLimitDown - 1; if ((LODngtvX && i < LODLimitDown) || (LODpstvX && i > LODLimitUp)) { axisLODValue = l + 1 + LODValue; } lodI = axisLODValue; } // map current index index = mod(deltaSubZ + stepJ, mapSubZ) * mapSubX + mod(deltaSubX + stepI, mapSubX); terIndex = mod(deltaSubZ + stepJ, terrainIdx) * terrainIdx + mod(deltaSubX + stepI, terrainIdx); // related i