react-babylonjs-x
Version:
React for Babylon.js
855 lines (853 loc) • 792 kB
JavaScript
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