瀏覽代碼

Merge pull request #7755 from BabylonJS/master

Nightly
mergify[bot] 5 年之前
父節點
當前提交
1cdf799215
共有 44 個文件被更改,包括 1749 次插入271 次删除
  1. 6 6
      dist/preview release/babylon.d.ts
  2. 1 1
      dist/preview release/babylon.js
  3. 100 86
      dist/preview release/babylon.max.js
  4. 1 1
      dist/preview release/babylon.max.js.map
  5. 13 12
      dist/preview release/babylon.module.d.ts
  6. 6 6
      dist/preview release/documentation.d.ts
  7. 6 6
      dist/preview release/inspector/babylon.inspector.bundle.js
  8. 498 38
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  9. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  10. 114 0
      dist/preview release/inspector/babylon.inspector.d.ts
  11. 274 0
      dist/preview release/inspector/babylon.inspector.module.d.ts
  12. 2 2
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  13. 30 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  14. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  15. 1 1
      dist/preview release/packagesSizeBaseLine.json
  16. 13 12
      dist/preview release/viewer/babylon.module.d.ts
  17. 15 15
      dist/preview release/viewer/babylon.viewer.js
  18. 1 1
      dist/preview release/viewer/babylon.viewer.max.js
  19. 2 0
      dist/preview release/what's new.md
  20. 2 1
      inspector/src/components/actionTabs/lines/checkBoxLineComponent.tsx
  21. 2 1
      inspector/src/components/actionTabs/lines/floatLineComponent.tsx
  22. 85 0
      inspector/src/components/actionTabs/lines/meshPickerComponent.tsx
  23. 3 2
      inspector/src/components/actionTabs/lines/sliderLineComponent.tsx
  24. 2 1
      inspector/src/components/actionTabs/lines/vector3LineComponent.tsx
  25. 37 0
      inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/boxEmitterGridComponent.tsx
  26. 39 0
      inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/coneEmitterGridComponent.tsx
  27. 38 0
      inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/cylinderEmitterGridComponent.tsx
  28. 37 0
      inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/hemisphericEmitterGridComponent.tsx
  29. 52 0
      inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/meshEmitterGridComponent.tsx
  30. 160 17
      inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/particleSystemPropertyGridComponent.tsx
  31. 35 0
      inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/pointEmitterGridComponent.tsx
  32. 37 0
      inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/sphereEmitterGridComponent.tsx
  33. 33 19
      inspector/src/components/replayRecorder.ts
  34. 22 0
      nodeEditor/src/diagram/graphCanvas.scss
  35. 32 3
      nodeEditor/src/diagram/graphFrame.ts
  36. 5 5
      src/Engines/nativeEngine.ts
  37. 2 3
      src/Layers/effectLayer.ts
  38. 2 4
      src/Lights/Shadows/shadowGenerator.ts
  39. 4 4
      src/Meshes/mesh.ts
  40. 27 10
      src/Particles/EmitterTypes/meshParticleEmitter.ts
  41. 2 3
      src/PostProcesses/volumetricLightScatteringPostProcess.ts
  42. 2 3
      src/Rendering/depthRenderer.ts
  43. 2 2
      src/Rendering/geometryBufferRenderer.ts
  44. 2 3
      src/Rendering/outlineRenderer.ts

+ 6 - 6
dist/preview release/babylon.d.ts

@@ -12839,12 +12839,11 @@ declare module BABYLON {
      * It emits the particles randomly between 2 given directions.
      */
     export class MeshParticleEmitter implements IParticleEmitterType {
-        /** Defines the mesh to use as source */
-        mesh?: AbstractMesh | undefined;
         private _indices;
         private _positions;
         private _normals;
         private _storedNormal;
+        private _mesh;
         /**
          * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
          */
@@ -12857,13 +12856,14 @@ declare module BABYLON {
          * Gets or sets a boolean indicating that particle directions must be built from mesh face normals
          */
         useMeshNormalsForDirection: boolean;
+        /** Defines the mesh to use as source */
+        get mesh(): Nullable<AbstractMesh>;
+        set mesh(value: Nullable<AbstractMesh>);
         /**
          * Creates a new instance MeshParticleEmitter
          * @param mesh defines the mesh to use as source
          */
-        constructor(
-        /** Defines the mesh to use as source */
-        mesh?: AbstractMesh | undefined);
+        constructor(mesh?: Nullable<AbstractMesh>);
         /**
          * Called by the particle System when the direction is computed for the created particle.
          * @param worldMatrix is the world matrix of the particle system
@@ -24812,7 +24812,7 @@ declare module BABYLON {
         /** @hidden */
         _processInstancedBuffers(visibleInstances: InstancedMesh[], renderSelf: boolean): void;
         /** @hidden */
-        _processRendering(subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
+        _processRendering(renderingMesh: AbstractMesh, subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
         /** @hidden */
         _rebuild(): void;
         /** @hidden */

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/babylon.js


File diff suppressed because it is too large
+ 100 - 86
dist/preview release/babylon.max.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/babylon.max.js.map


+ 13 - 12
dist/preview release/babylon.module.d.ts

@@ -13137,6 +13137,7 @@ declare module "babylonjs/Particles/EmitterTypes/meshParticleEmitter" {
     import { Effect } from "babylonjs/Materials/effect";
     import { Particle } from "babylonjs/Particles/particle";
     import { IParticleEmitterType } from "babylonjs/Particles/EmitterTypes/IParticleEmitterType";
+    import { Nullable } from "babylonjs/types";
     import { Scene } from "babylonjs/scene";
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     /**
@@ -13144,12 +13145,11 @@ declare module "babylonjs/Particles/EmitterTypes/meshParticleEmitter" {
      * It emits the particles randomly between 2 given directions.
      */
     export class MeshParticleEmitter implements IParticleEmitterType {
-        /** Defines the mesh to use as source */
-        mesh?: AbstractMesh | undefined;
         private _indices;
         private _positions;
         private _normals;
         private _storedNormal;
+        private _mesh;
         /**
          * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
          */
@@ -13162,13 +13162,14 @@ declare module "babylonjs/Particles/EmitterTypes/meshParticleEmitter" {
          * Gets or sets a boolean indicating that particle directions must be built from mesh face normals
          */
         useMeshNormalsForDirection: boolean;
+        /** Defines the mesh to use as source */
+        get mesh(): Nullable<AbstractMesh>;
+        set mesh(value: Nullable<AbstractMesh>);
         /**
          * Creates a new instance MeshParticleEmitter
          * @param mesh defines the mesh to use as source
          */
-        constructor(
-        /** Defines the mesh to use as source */
-        mesh?: AbstractMesh | undefined);
+        constructor(mesh?: Nullable<AbstractMesh>);
         /**
          * Called by the particle System when the direction is computed for the created particle.
          * @param worldMatrix is the world matrix of the particle system
@@ -25559,7 +25560,7 @@ declare module "babylonjs/Meshes/mesh" {
         /** @hidden */
         _processInstancedBuffers(visibleInstances: InstancedMesh[], renderSelf: boolean): void;
         /** @hidden */
-        _processRendering(subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
+        _processRendering(renderingMesh: AbstractMesh, subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
         /** @hidden */
         _rebuild(): void;
         /** @hidden */
@@ -86293,12 +86294,11 @@ declare module BABYLON {
      * It emits the particles randomly between 2 given directions.
      */
     export class MeshParticleEmitter implements IParticleEmitterType {
-        /** Defines the mesh to use as source */
-        mesh?: AbstractMesh | undefined;
         private _indices;
         private _positions;
         private _normals;
         private _storedNormal;
+        private _mesh;
         /**
          * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
          */
@@ -86311,13 +86311,14 @@ declare module BABYLON {
          * Gets or sets a boolean indicating that particle directions must be built from mesh face normals
          */
         useMeshNormalsForDirection: boolean;
+        /** Defines the mesh to use as source */
+        get mesh(): Nullable<AbstractMesh>;
+        set mesh(value: Nullable<AbstractMesh>);
         /**
          * Creates a new instance MeshParticleEmitter
          * @param mesh defines the mesh to use as source
          */
-        constructor(
-        /** Defines the mesh to use as source */
-        mesh?: AbstractMesh | undefined);
+        constructor(mesh?: Nullable<AbstractMesh>);
         /**
          * Called by the particle System when the direction is computed for the created particle.
          * @param worldMatrix is the world matrix of the particle system
@@ -98266,7 +98267,7 @@ declare module BABYLON {
         /** @hidden */
         _processInstancedBuffers(visibleInstances: InstancedMesh[], renderSelf: boolean): void;
         /** @hidden */
-        _processRendering(subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
+        _processRendering(renderingMesh: AbstractMesh, subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
         /** @hidden */
         _rebuild(): void;
         /** @hidden */

+ 6 - 6
dist/preview release/documentation.d.ts

@@ -12839,12 +12839,11 @@ declare module BABYLON {
      * It emits the particles randomly between 2 given directions.
      */
     export class MeshParticleEmitter implements IParticleEmitterType {
-        /** Defines the mesh to use as source */
-        mesh?: AbstractMesh | undefined;
         private _indices;
         private _positions;
         private _normals;
         private _storedNormal;
+        private _mesh;
         /**
          * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
          */
@@ -12857,13 +12856,14 @@ declare module BABYLON {
          * Gets or sets a boolean indicating that particle directions must be built from mesh face normals
          */
         useMeshNormalsForDirection: boolean;
+        /** Defines the mesh to use as source */
+        get mesh(): Nullable<AbstractMesh>;
+        set mesh(value: Nullable<AbstractMesh>);
         /**
          * Creates a new instance MeshParticleEmitter
          * @param mesh defines the mesh to use as source
          */
-        constructor(
-        /** Defines the mesh to use as source */
-        mesh?: AbstractMesh | undefined);
+        constructor(mesh?: Nullable<AbstractMesh>);
         /**
          * Called by the particle System when the direction is computed for the created particle.
          * @param worldMatrix is the world matrix of the particle system
@@ -24812,7 +24812,7 @@ declare module BABYLON {
         /** @hidden */
         _processInstancedBuffers(visibleInstances: InstancedMesh[], renderSelf: boolean): void;
         /** @hidden */
-        _processRendering(subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
+        _processRendering(renderingMesh: AbstractMesh, subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
         /** @hidden */
         _rebuild(): void;
         /** @hidden */

File diff suppressed because it is too large
+ 6 - 6
dist/preview release/inspector/babylon.inspector.bundle.js


+ 498 - 38
dist/preview release/inspector/babylon.inspector.bundle.max.js

@@ -40867,6 +40867,7 @@ var CheckBoxLineComponent = /** @class */ (function (_super) {
         return false;
     };
     CheckBoxLineComponent.prototype.onChange = function () {
+        var _a;
         this._localChange = true;
         if (this.props.onSelect) {
             this.props.onSelect(!this.state.isSelected);
@@ -40874,7 +40875,7 @@ var CheckBoxLineComponent = /** @class */ (function (_super) {
         else {
             if (this.props.onPropertyChangedObservable) {
                 this.props.onPropertyChangedObservable.notifyObservers({
-                    object: this.props.target,
+                    object: (_a = this.props.replaySourceReplacement, (_a !== null && _a !== void 0 ? _a : this.props.target)),
                     property: this.props.propertyName,
                     value: !this.state.isSelected,
                     initialValue: this.state.isSelected
@@ -41337,6 +41338,7 @@ var FloatLineComponent = /** @class */ (function (_super) {
         return false;
     };
     FloatLineComponent.prototype.raiseOnPropertyChanged = function (newValue, previousValue) {
+        var _a;
         if (this.props.onChange) {
             this.props.onChange(newValue);
         }
@@ -41344,7 +41346,7 @@ var FloatLineComponent = /** @class */ (function (_super) {
             return;
         }
         this.props.onPropertyChangedObservable.notifyObservers({
-            object: this.props.target,
+            object: (_a = this.props.replaySourceReplacement, (_a !== null && _a !== void 0 ? _a : this.props.target)),
             property: this.props.propertyName,
             value: newValue,
             initialValue: previousValue
@@ -41405,6 +41407,77 @@ var FloatLineComponent = /** @class */ (function (_super) {
 
 /***/ }),
 
+/***/ "./components/actionTabs/lines/meshPickerComponent.tsx":
+/*!*************************************************************!*\
+  !*** ./components/actionTabs/lines/meshPickerComponent.tsx ***!
+  \*************************************************************/
+/*! exports provided: MeshPickerComponent */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshPickerComponent", function() { return MeshPickerComponent; });
+/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _optionsLineComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./optionsLineComponent */ "./components/actionTabs/lines/optionsLineComponent.tsx");
+
+
+
+var MeshPickerComponent = /** @class */ (function (_super) {
+    Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(MeshPickerComponent, _super);
+    function MeshPickerComponent(props) {
+        return _super.call(this, props) || this;
+    }
+    MeshPickerComponent.prototype.render = function () {
+        var _this = this;
+        var meshEmitters = this.props.scene.meshes.filter(function (m) { return !!m.name; });
+        meshEmitters.sort(function (a, b) { return a.name.localeCompare(b.name); });
+        var emitterOptions = [
+            { label: "None", value: -1 },
+        ];
+        meshEmitters.sort(function (a, b) { return a.name.localeCompare(b.name); });
+        emitterOptions.push.apply(emitterOptions, meshEmitters.map(function (v, i) {
+            return { label: v.name, value: i };
+        }));
+        return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](react__WEBPACK_IMPORTED_MODULE_1__["Fragment"], null,
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_optionsLineComponent__WEBPACK_IMPORTED_MODULE_2__["OptionsLineComponent"], { label: this.props.label, options: emitterOptions, target: this.props.target, propertyName: this.props.property, noDirectUpdate: true, onSelect: function (value) {
+                    var _a;
+                    var currentState = _this.props.target[_this.props.property];
+                    switch (value) {
+                        case -1:
+                            _this.props.target[_this.props.property] = null;
+                            break;
+                        default:
+                            _this.props.target[_this.props.property] = meshEmitters[value];
+                    }
+                    if (_this.props.onPropertyChangedObservable) {
+                        _this.props.onPropertyChangedObservable.notifyObservers({
+                            object: (_a = _this.props.replaySourceReplacement, (_a !== null && _a !== void 0 ? _a : _this.props.target)),
+                            property: _this.props.property,
+                            value: _this.props.target[_this.props.property],
+                            initialValue: currentState
+                        });
+                    }
+                    _this.forceUpdate();
+                }, extractValue: function () {
+                    if (!_this.props.target[_this.props.property]) {
+                        return -1;
+                    }
+                    var meshIndex = meshEmitters.indexOf(_this.props.target[_this.props.property]);
+                    if (meshIndex > -1) {
+                        return meshIndex;
+                    }
+                    return -1;
+                } })));
+    };
+    return MeshPickerComponent;
+}(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
+
+
+
+/***/ }),
+
 /***/ "./components/actionTabs/lines/messageLineComponent.tsx":
 /*!**************************************************************!*\
   !*** ./components/actionTabs/lines/messageLineComponent.tsx ***!
@@ -41838,6 +41911,7 @@ var SliderLineComponent = /** @class */ (function (_super) {
         return false;
     };
     SliderLineComponent.prototype.onChange = function (newValueString) {
+        var _a;
         this._localChange = true;
         var newValue = parseFloat(newValueString);
         if (this.props.useEuler) {
@@ -41846,7 +41920,7 @@ var SliderLineComponent = /** @class */ (function (_super) {
         if (this.props.target) {
             if (this.props.onPropertyChangedObservable) {
                 this.props.onPropertyChangedObservable.notifyObservers({
-                    object: this.props.target,
+                    object: (_a = this.props.replaySourceReplacement, (_a !== null && _a !== void 0 ? _a : this.props.target)),
                     property: this.props.propertyName,
                     value: newValue,
                     initialValue: this.state.value
@@ -42545,6 +42619,7 @@ var Vector3LineComponent = /** @class */ (function (_super) {
         this.setState({ isExpanded: !this.state.isExpanded });
     };
     Vector3LineComponent.prototype.raiseOnPropertyChanged = function (previousValue) {
+        var _a;
         if (this.props.onChange) {
             this.props.onChange(this.state.value);
         }
@@ -42552,7 +42627,7 @@ var Vector3LineComponent = /** @class */ (function (_super) {
             return;
         }
         this.props.onPropertyChangedObservable.notifyObservers({
-            object: this.props.target,
+            object: (_a = this.props.replaySourceReplacement, (_a !== null && _a !== void 0 ? _a : this.props.target)),
             property: this.props.propertyName,
             value: this.state.value,
             initialValue: previousValue
@@ -46838,6 +46913,202 @@ var TransformNodePropertyGridComponent = /** @class */ (function (_super) {
 
 /***/ }),
 
+/***/ "./components/actionTabs/tabs/propertyGrids/particleSystems/boxEmitterGridComponent.tsx":
+/*!**********************************************************************************************!*\
+  !*** ./components/actionTabs/tabs/propertyGrids/particleSystems/boxEmitterGridComponent.tsx ***!
+  \**********************************************************************************************/
+/*! exports provided: BoxEmitterGridComponent */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BoxEmitterGridComponent", function() { return BoxEmitterGridComponent; });
+/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../lines/vector3LineComponent */ "./components/actionTabs/lines/vector3LineComponent.tsx");
+
+
+
+var BoxEmitterGridComponent = /** @class */ (function (_super) {
+    Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(BoxEmitterGridComponent, _super);
+    function BoxEmitterGridComponent(props) {
+        return _super.call(this, props) || this;
+    }
+    BoxEmitterGridComponent.prototype.render = function () {
+        var emitter = this.props.emitter;
+        return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](react__WEBPACK_IMPORTED_MODULE_1__["Fragment"], null,
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_2__["Vector3LineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Direction 1", target: emitter, propertyName: "direction1", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_2__["Vector3LineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Direction 2", target: emitter, propertyName: "direction2", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_2__["Vector3LineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Min emit box", target: emitter, propertyName: "minEmitBox", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_2__["Vector3LineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Max emit box", target: emitter, propertyName: "maxEmitBox", onPropertyChangedObservable: this.props.onPropertyChangedObservable })));
+    };
+    return BoxEmitterGridComponent;
+}(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
+
+
+
+/***/ }),
+
+/***/ "./components/actionTabs/tabs/propertyGrids/particleSystems/coneEmitterGridComponent.tsx":
+/*!***********************************************************************************************!*\
+  !*** ./components/actionTabs/tabs/propertyGrids/particleSystems/coneEmitterGridComponent.tsx ***!
+  \***********************************************************************************************/
+/*! exports provided: ConeEmitterGridComponent */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ConeEmitterGridComponent", function() { return ConeEmitterGridComponent; });
+/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../lines/sliderLineComponent */ "./components/actionTabs/lines/sliderLineComponent.tsx");
+/* harmony import */ var _lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../lines/checkBoxLineComponent */ "./components/actionTabs/lines/checkBoxLineComponent.tsx");
+
+
+
+
+var ConeEmitterGridComponent = /** @class */ (function (_super) {
+    Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(ConeEmitterGridComponent, _super);
+    function ConeEmitterGridComponent(props) {
+        return _super.call(this, props) || this;
+    }
+    ConeEmitterGridComponent.prototype.render = function () {
+        var emitter = this.props.emitter;
+        return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](react__WEBPACK_IMPORTED_MODULE_1__["Fragment"], null,
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_2__["SliderLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Radius range", target: emitter, propertyName: "radiusRange", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_2__["SliderLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Height range", target: emitter, propertyName: "heightRange", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_3__["CheckBoxLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Emit from spawn point only", target: emitter, propertyName: "emitFromSpawnPointOnly", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_2__["SliderLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Direction randomizer", target: emitter, propertyName: "directionRandomizer", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable })));
+    };
+    return ConeEmitterGridComponent;
+}(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
+
+
+
+/***/ }),
+
+/***/ "./components/actionTabs/tabs/propertyGrids/particleSystems/cylinderEmitterGridComponent.tsx":
+/*!***************************************************************************************************!*\
+  !*** ./components/actionTabs/tabs/propertyGrids/particleSystems/cylinderEmitterGridComponent.tsx ***!
+  \***************************************************************************************************/
+/*! exports provided: CylinderEmitterGridComponent */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CylinderEmitterGridComponent", function() { return CylinderEmitterGridComponent; });
+/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../lines/sliderLineComponent */ "./components/actionTabs/lines/sliderLineComponent.tsx");
+/* harmony import */ var _lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../lines/floatLineComponent */ "./components/actionTabs/lines/floatLineComponent.tsx");
+
+
+
+
+var CylinderEmitterGridComponent = /** @class */ (function (_super) {
+    Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(CylinderEmitterGridComponent, _super);
+    function CylinderEmitterGridComponent(props) {
+        return _super.call(this, props) || this;
+    }
+    CylinderEmitterGridComponent.prototype.render = function () {
+        var emitter = this.props.emitter;
+        return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](react__WEBPACK_IMPORTED_MODULE_1__["Fragment"], null,
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_3__["FloatLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, lockObject: this.props.lockObject, label: "Radius", target: emitter, propertyName: "radius", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_3__["FloatLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, lockObject: this.props.lockObject, label: "Height", target: emitter, propertyName: "height", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_2__["SliderLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Radius range", target: emitter, propertyName: "radiusRange", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_2__["SliderLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Direction randomizer", target: emitter, propertyName: "directionRandomizer", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable })));
+    };
+    return CylinderEmitterGridComponent;
+}(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
+
+
+
+/***/ }),
+
+/***/ "./components/actionTabs/tabs/propertyGrids/particleSystems/hemisphericEmitterGridComponent.tsx":
+/*!******************************************************************************************************!*\
+  !*** ./components/actionTabs/tabs/propertyGrids/particleSystems/hemisphericEmitterGridComponent.tsx ***!
+  \******************************************************************************************************/
+/*! exports provided: HemisphericEmitterGridComponent */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "HemisphericEmitterGridComponent", function() { return HemisphericEmitterGridComponent; });
+/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../lines/sliderLineComponent */ "./components/actionTabs/lines/sliderLineComponent.tsx");
+/* harmony import */ var _lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../lines/floatLineComponent */ "./components/actionTabs/lines/floatLineComponent.tsx");
+
+
+
+
+var HemisphericEmitterGridComponent = /** @class */ (function (_super) {
+    Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(HemisphericEmitterGridComponent, _super);
+    function HemisphericEmitterGridComponent(props) {
+        return _super.call(this, props) || this;
+    }
+    HemisphericEmitterGridComponent.prototype.render = function () {
+        var emitter = this.props.emitter;
+        return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](react__WEBPACK_IMPORTED_MODULE_1__["Fragment"], null,
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_3__["FloatLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, lockObject: this.props.lockObject, label: "Radius", target: emitter, propertyName: "radius", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_2__["SliderLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Radius range", target: emitter, propertyName: "radiusRange", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_2__["SliderLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Direction randomizer", target: emitter, propertyName: "directionRandomizer", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable })));
+    };
+    return HemisphericEmitterGridComponent;
+}(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
+
+
+
+/***/ }),
+
+/***/ "./components/actionTabs/tabs/propertyGrids/particleSystems/meshEmitterGridComponent.tsx":
+/*!***********************************************************************************************!*\
+  !*** ./components/actionTabs/tabs/propertyGrids/particleSystems/meshEmitterGridComponent.tsx ***!
+  \***********************************************************************************************/
+/*! exports provided: MeshEmitterGridComponent */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MeshEmitterGridComponent", function() { return MeshEmitterGridComponent; });
+/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../lines/vector3LineComponent */ "./components/actionTabs/lines/vector3LineComponent.tsx");
+/* harmony import */ var _lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../lines/checkBoxLineComponent */ "./components/actionTabs/lines/checkBoxLineComponent.tsx");
+/* harmony import */ var _lines_meshPickerComponent__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../../lines/meshPickerComponent */ "./components/actionTabs/lines/meshPickerComponent.tsx");
+
+
+
+
+
+var MeshEmitterGridComponent = /** @class */ (function (_super) {
+    Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(MeshEmitterGridComponent, _super);
+    function MeshEmitterGridComponent(props) {
+        return _super.call(this, props) || this;
+    }
+    MeshEmitterGridComponent.prototype.render = function () {
+        var emitter = this.props.emitter;
+        return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](react__WEBPACK_IMPORTED_MODULE_1__["Fragment"], null,
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_meshPickerComponent__WEBPACK_IMPORTED_MODULE_4__["MeshPickerComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, globalState: this.props.globalState, label: "Source", scene: this.props.scene, onPropertyChangedObservable: this.props.onPropertyChangedObservable, target: this.props.emitter, property: "mesh" }),
+            !emitter.useMeshNormalsForDirection &&
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_2__["Vector3LineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Direction 1", target: emitter, propertyName: "direction1", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            !emitter.useMeshNormalsForDirection &&
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_2__["Vector3LineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Direction 2", target: emitter, propertyName: "direction2", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_3__["CheckBoxLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Use normals for direction", target: emitter, propertyName: "useMeshNormalsForDirection", onPropertyChangedObservable: this.props.onPropertyChangedObservable })));
+    };
+    return MeshEmitterGridComponent;
+}(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
+
+
+
+/***/ }),
+
 /***/ "./components/actionTabs/tabs/propertyGrids/particleSystems/particleSystemPropertyGridComponent.tsx":
 /*!**********************************************************************************************************!*\
   !*** ./components/actionTabs/tabs/propertyGrids/particleSystems/particleSystemPropertyGridComponent.tsx ***!
@@ -46864,6 +47135,22 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../../lines/vector3LineComponent */ "./components/actionTabs/lines/vector3LineComponent.tsx");
 /* harmony import */ var _lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../../../lines/checkBoxLineComponent */ "./components/actionTabs/lines/checkBoxLineComponent.tsx");
 /* harmony import */ var _lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../../../lines/sliderLineComponent */ "./components/actionTabs/lines/sliderLineComponent.tsx");
+/* harmony import */ var _boxEmitterGridComponent__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./boxEmitterGridComponent */ "./components/actionTabs/tabs/propertyGrids/particleSystems/boxEmitterGridComponent.tsx");
+/* harmony import */ var _coneEmitterGridComponent__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./coneEmitterGridComponent */ "./components/actionTabs/tabs/propertyGrids/particleSystems/coneEmitterGridComponent.tsx");
+/* harmony import */ var _cylinderEmitterGridComponent__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./cylinderEmitterGridComponent */ "./components/actionTabs/tabs/propertyGrids/particleSystems/cylinderEmitterGridComponent.tsx");
+/* harmony import */ var _hemisphericEmitterGridComponent__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./hemisphericEmitterGridComponent */ "./components/actionTabs/tabs/propertyGrids/particleSystems/hemisphericEmitterGridComponent.tsx");
+/* harmony import */ var _pointEmitterGridComponent__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./pointEmitterGridComponent */ "./components/actionTabs/tabs/propertyGrids/particleSystems/pointEmitterGridComponent.tsx");
+/* harmony import */ var _sphereEmitterGridComponent__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./sphereEmitterGridComponent */ "./components/actionTabs/tabs/propertyGrids/particleSystems/sphereEmitterGridComponent.tsx");
+/* harmony import */ var _meshEmitterGridComponent__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./meshEmitterGridComponent */ "./components/actionTabs/tabs/propertyGrids/particleSystems/meshEmitterGridComponent.tsx");
+
+
+
+
+
+
+
+
+
 
 
 
@@ -46889,7 +47176,42 @@ var ParticleSystemPropertyGridComponent = /** @class */ (function (_super) {
     function ParticleSystemPropertyGridComponent(props) {
         return _super.call(this, props) || this;
     }
+    ParticleSystemPropertyGridComponent.prototype.renderEmitter = function () {
+        var _a;
+        var system = this.props.system;
+        var replaySource = "particlesystem.particleEmitterType";
+        switch ((_a = system.particleEmitterType) === null || _a === void 0 ? void 0 : _a.getClassName()) {
+            case "BoxParticleEmitter":
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_boxEmitterGridComponent__WEBPACK_IMPORTED_MODULE_14__["BoxEmitterGridComponent"], { replaySourceReplacement: replaySource, globalState: this.props.globalState, emitter: system.particleEmitterType, onPropertyChangedObservable: this.props.onPropertyChangedObservable }));
+            case "ConeParticleEmitter":
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_coneEmitterGridComponent__WEBPACK_IMPORTED_MODULE_15__["ConeEmitterGridComponent"], { replaySourceReplacement: replaySource, globalState: this.props.globalState, emitter: system.particleEmitterType, onPropertyChangedObservable: this.props.onPropertyChangedObservable }));
+            case "CylinderParticleEmitter":
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_cylinderEmitterGridComponent__WEBPACK_IMPORTED_MODULE_16__["CylinderEmitterGridComponent"], { replaySourceReplacement: replaySource, lockObject: this.props.lockObject, globalState: this.props.globalState, emitter: system.particleEmitterType, onPropertyChangedObservable: this.props.onPropertyChangedObservable }));
+            case "HemisphericParticleEmitter":
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_hemisphericEmitterGridComponent__WEBPACK_IMPORTED_MODULE_17__["HemisphericEmitterGridComponent"], { replaySourceReplacement: replaySource, lockObject: this.props.lockObject, globalState: this.props.globalState, emitter: system.particleEmitterType, onPropertyChangedObservable: this.props.onPropertyChangedObservable }));
+            case "MeshParticleEmitter":
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_meshEmitterGridComponent__WEBPACK_IMPORTED_MODULE_20__["MeshEmitterGridComponent"], { replaySourceReplacement: replaySource, lockObject: this.props.lockObject, scene: system.getScene(), globalState: this.props.globalState, emitter: system.particleEmitterType, onPropertyChangedObservable: this.props.onPropertyChangedObservable }));
+            case "PointParticleEmitter":
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_pointEmitterGridComponent__WEBPACK_IMPORTED_MODULE_18__["PointEmitterGridComponent"], { replaySourceReplacement: replaySource, lockObject: this.props.lockObject, globalState: this.props.globalState, emitter: system.particleEmitterType, onPropertyChangedObservable: this.props.onPropertyChangedObservable }));
+            case "SphereParticleEmitter":
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_sphereEmitterGridComponent__WEBPACK_IMPORTED_MODULE_19__["SphereEmitterGridComponent"], { replaySourceReplacement: replaySource, lockObject: this.props.lockObject, globalState: this.props.globalState, emitter: system.particleEmitterType, onPropertyChangedObservable: this.props.onPropertyChangedObservable }));
+        }
+        return null;
+    };
+    ParticleSystemPropertyGridComponent.prototype.raiseOnPropertyChanged = function (property, newValue, previousValue) {
+        if (!this.props.onPropertyChangedObservable) {
+            return;
+        }
+        var system = this.props.system;
+        this.props.onPropertyChangedObservable.notifyObservers({
+            object: system,
+            property: property,
+            value: newValue,
+            initialValue: previousValue
+        });
+    };
     ParticleSystemPropertyGridComponent.prototype.render = function () {
+        var _this = this;
         var system = this.props.system;
         var blendModeOptions = [
             { label: "Add", value: babylonjs_Particles_particleSystem__WEBPACK_IMPORTED_MODULE_9__["ParticleSystem"].BLENDMODE_ADD },
@@ -46903,14 +47225,25 @@ var ParticleSystemPropertyGridComponent = /** @class */ (function (_super) {
             { label: "Cone", value: 1 },
             { label: "Cylinder", value: 2 },
             { label: "Hemispheric", value: 3 },
-            { label: "Point", value: 4 },
-            { label: "Sphere", value: 5 },
+            { label: "Mesh", value: 4 },
+            { label: "Point", value: 5 },
+            { label: "Sphere", value: 6 },
+        ];
+        var meshEmitters = this.props.system.getScene().meshes.filter(function (m) { return !!m.name; });
+        var emitterOptions = [
+            { label: "None", value: -1 },
+            { label: "Vector3", value: 0 }
         ];
+        meshEmitters.sort(function (a, b) { return a.name.localeCompare(b.name); });
+        emitterOptions.push.apply(emitterOptions, meshEmitters.map(function (v, i) {
+            return { label: v.name, value: i + 1 };
+        }));
         return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { className: "pane" },
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_customPropertyGridComponent__WEBPACK_IMPORTED_MODULE_4__["CustomPropertyGridComponent"], { globalState: this.props.globalState, target: system, lockObject: this.props.lockObject, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__["LineContainerComponent"], { globalState: this.props.globalState, title: "GENERAL" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "ID", value: system.id }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Class", value: system.getClassName() }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Capacity", value: system.getCapacity().toString() }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textureLinkLineComponent__WEBPACK_IMPORTED_MODULE_7__["TextureLinkLineComponent"], { label: "Texture", texture: system.particleTexture, onSelectionChangedObservable: this.props.onSelectionChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_optionsLineComponent__WEBPACK_IMPORTED_MODULE_8__["OptionsLineComponent"], { label: "Blend mode", options: blendModeOptions, target: system, propertyName: "blendMode", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_11__["Vector3LineComponent"], { label: "Gravity", target: system, propertyName: "gravity", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
@@ -46926,8 +47259,41 @@ var ParticleSystemPropertyGridComponent = /** @class */ (function (_super) {
                             system.start();
                         }
                     } })),
-            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__["LineContainerComponent"], { globalState: this.props.globalState, title: "Emitter" },
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__["LineContainerComponent"], { globalState: this.props.globalState, title: "EMITTER" },
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_optionsLineComponent__WEBPACK_IMPORTED_MODULE_8__["OptionsLineComponent"], { label: "Emitter", options: emitterOptions, target: system, propertyName: "emitter", noDirectUpdate: true, onSelect: function (value) {
+                        switch (value) {
+                            case -1:
+                                _this.raiseOnPropertyChanged("emitter", null, system.emitter);
+                                system.emitter = null;
+                                break;
+                            case 0:
+                                _this.raiseOnPropertyChanged("emitter", babylonjs_Particles_particleSystem__WEBPACK_IMPORTED_MODULE_9__["Vector3"].Zero(), system.emitter);
+                                system.emitter = babylonjs_Particles_particleSystem__WEBPACK_IMPORTED_MODULE_9__["Vector3"].Zero();
+                                break;
+                            default:
+                                _this.raiseOnPropertyChanged("emitter", meshEmitters[value - 1], system.emitter);
+                                system.emitter = meshEmitters[value - 1];
+                        }
+                        _this.forceUpdate();
+                    }, extractValue: function () {
+                        if (!system.emitter) {
+                            return -1;
+                        }
+                        if (system.emitter.x !== undefined) {
+                            return 0;
+                        }
+                        var meshIndex = meshEmitters.indexOf(system.emitter);
+                        if (meshIndex > -1) {
+                            return meshIndex + 1;
+                        }
+                        return -1;
+                    } }),
+                system.emitter && (system.emitter.x === undefined) &&
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__["TextLineComponent"], { label: "Link to emitter", value: system.emitter.name, onLink: function () { return _this.props.globalState.onSelectionChangedObservable.notifyObservers(system.emitter); } }),
+                system.emitter && (system.emitter.x !== undefined) &&
+                    react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_11__["Vector3LineComponent"], { label: "Position", target: system, propertyName: "emitter", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_optionsLineComponent__WEBPACK_IMPORTED_MODULE_8__["OptionsLineComponent"], { label: "Type", options: particleEmitterTypeOptions, target: system, propertyName: "particleEmitterType", noDirectUpdate: true, onSelect: function (value) {
+                        var currentType = system.particleEmitterType;
                         switch (value) {
                             case 0:
                                 system.particleEmitterType = new babylonjs_Particles_particleSystem__WEBPACK_IMPORTED_MODULE_9__["BoxParticleEmitter"]();
@@ -46942,12 +47308,17 @@ var ParticleSystemPropertyGridComponent = /** @class */ (function (_super) {
                                 system.particleEmitterType = new babylonjs_Particles_particleSystem__WEBPACK_IMPORTED_MODULE_9__["HemisphericParticleEmitter"]();
                                 break;
                             case 4:
-                                system.particleEmitterType = new babylonjs_Particles_particleSystem__WEBPACK_IMPORTED_MODULE_9__["PointParticleEmitter"]();
+                                system.particleEmitterType = new babylonjs_Particles_particleSystem__WEBPACK_IMPORTED_MODULE_9__["MeshParticleEmitter"]();
                                 break;
                             case 5:
+                                system.particleEmitterType = new babylonjs_Particles_particleSystem__WEBPACK_IMPORTED_MODULE_9__["PointParticleEmitter"]();
+                                break;
+                            case 6:
                                 system.particleEmitterType = new babylonjs_Particles_particleSystem__WEBPACK_IMPORTED_MODULE_9__["SphereParticleEmitter"]();
                                 break;
                         }
+                        _this.raiseOnPropertyChanged("particleEmitterType", system.particleEmitterType, currentType);
+                        _this.forceUpdate();
                     }, extractValue: function () {
                         var _a;
                         switch ((_a = system.particleEmitterType) === null || _a === void 0 ? void 0 : _a.getClassName()) {
@@ -46959,13 +47330,20 @@ var ParticleSystemPropertyGridComponent = /** @class */ (function (_super) {
                                 return 2;
                             case "HemisphericParticleEmitter":
                                 return 3;
-                            case "PointParticleEmitter":
+                            case "MeshParticleEmitter":
                                 return 4;
-                            case "SphereParticleEmitter":
+                            case "PointParticleEmitter":
                                 return 5;
+                            case "SphereParticleEmitter":
+                                return 6;
                         }
                         return 0;
-                    }, onPropertyChangedObservable: this.props.onPropertyChangedObservable })),
+                    } }),
+                this.renderEmitter()),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__["LineContainerComponent"], { globalState: this.props.globalState, title: "EMISSION" },
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Rate", target: system, propertyName: "emitRate", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Min emit power", target: system, propertyName: "minEmitPower", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Max emit power", target: system, propertyName: "maxEmitPower", onPropertyChangedObservable: this.props.onPropertyChangedObservable })),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__["LineContainerComponent"], { globalState: this.props.globalState, title: "SIZE" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Min size", target: system, propertyName: "minSize", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Max size", target: system, propertyName: "maxSize", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
@@ -46976,10 +47354,6 @@ var ParticleSystemPropertyGridComponent = /** @class */ (function (_super) {
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__["LineContainerComponent"], { globalState: this.props.globalState, title: "LIFETIME" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Min lifetime", target: system, propertyName: "minLifeTime", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Max lifetime", target: system, propertyName: "maxLifeTime", onPropertyChangedObservable: this.props.onPropertyChangedObservable })),
-            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__["LineContainerComponent"], { globalState: this.props.globalState, title: "EMISSION" },
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Rate", target: system, propertyName: "emitRate", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Min emit power", target: system, propertyName: "minEmitPower", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
-                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__["FloatLineComponent"], { lockObject: this.props.lockObject, label: "Max emit power", target: system, propertyName: "maxEmitPower", onPropertyChangedObservable: this.props.onPropertyChangedObservable })),
             react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__["LineContainerComponent"], { globalState: this.props.globalState, title: "COLORS" },
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_color4LineComponent__WEBPACK_IMPORTED_MODULE_10__["Color4LineComponent"], { label: "Color 1", target: system, propertyName: "color1", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
                 react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_color4LineComponent__WEBPACK_IMPORTED_MODULE_10__["Color4LineComponent"], { label: "Color 2", target: system, propertyName: "color2", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
@@ -46997,6 +47371,79 @@ var ParticleSystemPropertyGridComponent = /** @class */ (function (_super) {
 
 /***/ }),
 
+/***/ "./components/actionTabs/tabs/propertyGrids/particleSystems/pointEmitterGridComponent.tsx":
+/*!************************************************************************************************!*\
+  !*** ./components/actionTabs/tabs/propertyGrids/particleSystems/pointEmitterGridComponent.tsx ***!
+  \************************************************************************************************/
+/*! exports provided: PointEmitterGridComponent */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PointEmitterGridComponent", function() { return PointEmitterGridComponent; });
+/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../lines/vector3LineComponent */ "./components/actionTabs/lines/vector3LineComponent.tsx");
+
+
+
+var PointEmitterGridComponent = /** @class */ (function (_super) {
+    Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(PointEmitterGridComponent, _super);
+    function PointEmitterGridComponent(props) {
+        return _super.call(this, props) || this;
+    }
+    PointEmitterGridComponent.prototype.render = function () {
+        var emitter = this.props.emitter;
+        return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](react__WEBPACK_IMPORTED_MODULE_1__["Fragment"], null,
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_2__["Vector3LineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Direction 1", target: emitter, propertyName: "direction1", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_vector3LineComponent__WEBPACK_IMPORTED_MODULE_2__["Vector3LineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Direction 2", target: emitter, propertyName: "direction2", onPropertyChangedObservable: this.props.onPropertyChangedObservable })));
+    };
+    return PointEmitterGridComponent;
+}(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
+
+
+
+/***/ }),
+
+/***/ "./components/actionTabs/tabs/propertyGrids/particleSystems/sphereEmitterGridComponent.tsx":
+/*!*************************************************************************************************!*\
+  !*** ./components/actionTabs/tabs/propertyGrids/particleSystems/sphereEmitterGridComponent.tsx ***!
+  \*************************************************************************************************/
+/*! exports provided: SphereEmitterGridComponent */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SphereEmitterGridComponent", function() { return SphereEmitterGridComponent; });
+/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../lines/floatLineComponent */ "./components/actionTabs/lines/floatLineComponent.tsx");
+/* harmony import */ var _lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../lines/sliderLineComponent */ "./components/actionTabs/lines/sliderLineComponent.tsx");
+
+
+
+
+var SphereEmitterGridComponent = /** @class */ (function (_super) {
+    Object(tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"])(SphereEmitterGridComponent, _super);
+    function SphereEmitterGridComponent(props) {
+        return _super.call(this, props) || this;
+    }
+    SphereEmitterGridComponent.prototype.render = function () {
+        var emitter = this.props.emitter;
+        return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](react__WEBPACK_IMPORTED_MODULE_1__["Fragment"], null,
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_2__["FloatLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, lockObject: this.props.lockObject, label: "Radius", target: emitter, propertyName: "radius", onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_3__["SliderLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Radius range", target: emitter, propertyName: "radiusRange", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_3__["SliderLineComponent"], { replaySourceReplacement: this.props.replaySourceReplacement, label: "Direction randomizer", target: emitter, propertyName: "directionRandomizer", minimum: 0, maximum: 1, step: 0.01, onPropertyChangedObservable: this.props.onPropertyChangedObservable })));
+    };
+    return SphereEmitterGridComponent;
+}(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
+
+
+
+/***/ }),
+
 /***/ "./components/actionTabs/tabs/propertyGrids/postProcesses/commonPostProcessPropertyGridComponent.tsx":
 /*!***********************************************************************************************************!*\
   !*** ./components/actionTabs/tabs/propertyGrids/postProcesses/commonPostProcessPropertyGridComponent.tsx ***!
@@ -48692,6 +49139,39 @@ var ReplayRecorder = /** @class */ (function () {
         this._previousObject = null;
         this._previousProperty = "";
     };
+    ReplayRecorder.prototype._getIndirectData = function (data) {
+        if (!data.getClassName) {
+            return data;
+        }
+        var indirectData = data.getClassName().toLowerCase();
+        if (data.id) {
+            if (indirectData === "Scene") {
+                indirectData = "scene";
+            }
+            else if (indirectData.indexOf("camera") > -1) {
+                indirectData = "scene.getCameraByID(\"" + data.id + "\")";
+            }
+            else if (indirectData.indexOf("mesh") > -1) {
+                indirectData = "scene.getMeshByID(\"" + data.id + "\")";
+            }
+            else if (indirectData.indexOf("light") > -1) {
+                indirectData = "scene.getLightByID(\"" + data.id + "\")";
+            }
+            else if (indirectData === "transformnode") {
+                indirectData = "scene.getTransformNodeByID(\"" + data.id + "\")";
+            }
+            else if (indirectData === "skeleton") {
+                indirectData = "scene.getSkeletonById(\"" + data.id + "\")";
+            }
+            else if (indirectData.indexOf("material") > -1) {
+                indirectData = "scene.getMaterialByID(\"" + data.id + "\")";
+            }
+        }
+        else {
+            indirectData = "new BABYLON." + data.getClassName() + "()";
+        }
+        return indirectData;
+    };
     ReplayRecorder.prototype.record = function (event) {
         if (!this._recordedCodeLines) {
             this._recordedCodeLines = [];
@@ -48715,30 +49195,10 @@ var ReplayRecorder = /** @class */ (function () {
         else if (value.b !== undefined) { // Color3
             value = "new BABYLON.Color3(" + value.r + ", " + value.g + ", " + value.b + ")";
         }
-        var target = event.object.getClassName().toLowerCase();
-        if (event.object.id) {
-            if (target === "Scene") {
-                target = "scene";
-            }
-            else if (target.indexOf("camera") > -1) {
-                target = "scene.getCameraByID(\"" + event.object.id + "\")";
-            }
-            else if (target.indexOf("mesh") > -1) {
-                target = "scene.getMeshByID(\"" + event.object.id + "\")";
-            }
-            else if (target.indexOf("light") > -1) {
-                target = "scene.getLightByID(\"" + event.object.id + "\")";
-            }
-            else if (target === "transformnode") {
-                target = "scene.getTransformNodeByID(\"" + event.object.id + "\")";
-            }
-            else if (target === "skeleton") {
-                target = "scene.getSkeletonById(\"" + event.object.id + "\")";
-            }
-            else if (target.indexOf("material") > -1) {
-                target = "scene.getMaterialByID(\"" + event.object.id + "\")";
-            }
+        else if (value.getClassName) {
+            value = this._getIndirectData(value);
         }
+        var target = this._getIndirectData(event.object);
         this._recordedCodeLines.push(target + "." + event.property + " = " + value + ";");
         this._previousObject = event.object;
         this._previousProperty = event.property;

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


+ 114 - 0
dist/preview release/inspector/babylon.inspector.d.ts

@@ -13,6 +13,7 @@ declare module INSPECTOR {
         private _previousObject;
         private _previousProperty;
         reset(): void;
+        private _getIndirectData;
         record(event: PropertyChangedEvent): void;
         export(): void;
     }
@@ -157,6 +158,7 @@ declare module INSPECTOR {
         isSelected?: () => boolean;
         onSelect?: (value: boolean) => void;
         onValueChanged?: () => void;
+        replaySourceReplacement?: string;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
     }
     export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponentProps, {
@@ -208,6 +210,7 @@ declare module INSPECTOR {
         useEuler?: boolean;
         onChange?: (value: number) => void;
         onInput?: (value: number) => void;
+        replaySourceReplacement?: string;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
         decimalCount?: number;
     }
@@ -321,6 +324,7 @@ declare module INSPECTOR {
         step?: number;
         onChange?: (newvalue: BABYLON.Vector3) => void;
         useEuler?: boolean;
+        replaySourceReplacement?: string;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
     }
     export class Vector3LineComponent extends React.Component<IVector3LineComponentProps, {
@@ -545,6 +549,7 @@ declare module INSPECTOR {
         lockObject?: LockObject;
         onChange?: (newValue: number) => void;
         isInteger?: boolean;
+        replaySourceReplacement?: string;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
         additionalClass?: string;
         step?: string;
@@ -1351,6 +1356,113 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    interface IBoxEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.BoxParticleEmitter;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class BoxEmitterGridComponent extends React.Component<IBoxEmitterGridComponentProps> {
+        constructor(props: IBoxEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IConeEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.ConeParticleEmitter;
+        onSelectionChangedObservable?: BABYLON.Observable<any>;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class ConeEmitterGridComponent extends React.Component<IConeEmitterGridComponentProps> {
+        constructor(props: IConeEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface ICylinderEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.CylinderParticleEmitter;
+        lockObject: LockObject;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class CylinderEmitterGridComponent extends React.Component<ICylinderEmitterGridComponentProps> {
+        constructor(props: ICylinderEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IHemisphericEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.HemisphericParticleEmitter;
+        lockObject: LockObject;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class HemisphericEmitterGridComponent extends React.Component<IHemisphericEmitterGridComponentProps> {
+        constructor(props: IHemisphericEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IPointEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.PointParticleEmitter;
+        lockObject: LockObject;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class PointEmitterGridComponent extends React.Component<IPointEmitterGridComponentProps> {
+        constructor(props: IPointEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface ISphereEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.SphereParticleEmitter;
+        lockObject: LockObject;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class SphereEmitterGridComponent extends React.Component<ISphereEmitterGridComponentProps> {
+        constructor(props: ISphereEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IMeshPickerComponentProps {
+        globalState: GlobalState;
+        target: any;
+        property: string;
+        scene: BABYLON.Scene;
+        label: string;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class MeshPickerComponent extends React.Component<IMeshPickerComponentProps> {
+        constructor(props: IMeshPickerComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IMeshEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.MeshParticleEmitter;
+        scene: BABYLON.Scene;
+        lockObject: LockObject;
+        onSelectionChangedObservable?: BABYLON.Observable<any>;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class MeshEmitterGridComponent extends React.Component<IMeshEmitterGridComponentProps> {
+        constructor(props: IMeshEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     interface IParticleSystemPropertyGridComponentProps {
         globalState: GlobalState;
         system: BABYLON.IParticleSystem;
@@ -1360,6 +1472,8 @@ declare module INSPECTOR {
     }
     export class ParticleSystemPropertyGridComponent extends React.Component<IParticleSystemPropertyGridComponentProps> {
         constructor(props: IParticleSystemPropertyGridComponentProps);
+        renderEmitter(): JSX.Element | null;
+        raiseOnPropertyChanged(property: string, newValue: any, previousValue: any): void;
         render(): JSX.Element;
     }
 }

+ 274 - 0
dist/preview release/inspector/babylon.inspector.module.d.ts

@@ -14,6 +14,7 @@ declare module "babylonjs-inspector/components/replayRecorder" {
         private _previousObject;
         private _previousProperty;
         reset(): void;
+        private _getIndirectData;
         record(event: PropertyChangedEvent): void;
         export(): void;
     }
@@ -184,6 +185,7 @@ declare module "babylonjs-inspector/components/actionTabs/lines/checkBoxLineComp
         isSelected?: () => boolean;
         onSelect?: (value: boolean) => void;
         onValueChanged?: () => void;
+        replaySourceReplacement?: string;
         onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
     }
     export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponentProps, {
@@ -242,6 +244,7 @@ declare module "babylonjs-inspector/components/actionTabs/lines/sliderLineCompon
         useEuler?: boolean;
         onChange?: (value: number) => void;
         onInput?: (value: number) => void;
+        replaySourceReplacement?: string;
         onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
         decimalCount?: number;
     }
@@ -367,6 +370,7 @@ declare module "babylonjs-inspector/components/actionTabs/lines/vector3LineCompo
         step?: number;
         onChange?: (newvalue: Vector3) => void;
         useEuler?: boolean;
+        replaySourceReplacement?: string;
         onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
     }
     export class Vector3LineComponent extends React.Component<IVector3LineComponentProps, {
@@ -637,6 +641,7 @@ declare module "babylonjs-inspector/components/actionTabs/lines/floatLineCompone
         lockObject?: LockObject;
         onChange?: (newValue: number) => void;
         isInteger?: boolean;
+        replaySourceReplacement?: string;
         onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
         additionalClass?: string;
         step?: string;
@@ -1750,6 +1755,159 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/mat
         render(): JSX.Element;
     }
 }
+declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/particleSystems/boxEmitterGridComponent" {
+    import * as React from "react";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { GlobalState } from "babylonjs-inspector/components/globalState";
+    import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
+    import { BoxParticleEmitter } from 'babylonjs/Particles/EmitterTypes/boxParticleEmitter';
+    interface IBoxEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BoxParticleEmitter;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    }
+    export class BoxEmitterGridComponent extends React.Component<IBoxEmitterGridComponentProps> {
+        constructor(props: IBoxEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/particleSystems/coneEmitterGridComponent" {
+    import * as React from "react";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { GlobalState } from "babylonjs-inspector/components/globalState";
+    import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
+    import { ConeParticleEmitter } from 'babylonjs/Particles/EmitterTypes/coneParticleEmitter';
+    interface IConeEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: ConeParticleEmitter;
+        onSelectionChangedObservable?: Observable<any>;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    }
+    export class ConeEmitterGridComponent extends React.Component<IConeEmitterGridComponentProps> {
+        constructor(props: IConeEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/particleSystems/cylinderEmitterGridComponent" {
+    import * as React from "react";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { GlobalState } from "babylonjs-inspector/components/globalState";
+    import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
+    import { CylinderParticleEmitter } from 'babylonjs/Particles/EmitterTypes/cylinderParticleEmitter';
+    import { LockObject } from "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/lockObject";
+    interface ICylinderEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: CylinderParticleEmitter;
+        lockObject: LockObject;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    }
+    export class CylinderEmitterGridComponent extends React.Component<ICylinderEmitterGridComponentProps> {
+        constructor(props: ICylinderEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/particleSystems/hemisphericEmitterGridComponent" {
+    import * as React from "react";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { GlobalState } from "babylonjs-inspector/components/globalState";
+    import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
+    import { LockObject } from "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/lockObject";
+    import { HemisphericParticleEmitter } from 'babylonjs/Particles/EmitterTypes/hemisphericParticleEmitter';
+    interface IHemisphericEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: HemisphericParticleEmitter;
+        lockObject: LockObject;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    }
+    export class HemisphericEmitterGridComponent extends React.Component<IHemisphericEmitterGridComponentProps> {
+        constructor(props: IHemisphericEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/particleSystems/pointEmitterGridComponent" {
+    import * as React from "react";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { GlobalState } from "babylonjs-inspector/components/globalState";
+    import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
+    import { LockObject } from "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/lockObject";
+    import { PointParticleEmitter } from 'babylonjs/Particles/EmitterTypes/pointParticleEmitter';
+    interface IPointEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: PointParticleEmitter;
+        lockObject: LockObject;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    }
+    export class PointEmitterGridComponent extends React.Component<IPointEmitterGridComponentProps> {
+        constructor(props: IPointEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/particleSystems/sphereEmitterGridComponent" {
+    import * as React from "react";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { GlobalState } from "babylonjs-inspector/components/globalState";
+    import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
+    import { LockObject } from "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/lockObject";
+    import { SphereParticleEmitter } from 'babylonjs/Particles/EmitterTypes/sphereParticleEmitter';
+    interface ISphereEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: SphereParticleEmitter;
+        lockObject: LockObject;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    }
+    export class SphereEmitterGridComponent extends React.Component<ISphereEmitterGridComponentProps> {
+        constructor(props: ISphereEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module "babylonjs-inspector/components/actionTabs/lines/meshPickerComponent" {
+    import * as React from "react";
+    import { GlobalState } from "babylonjs-inspector/components/globalState";
+    import { Observable } from 'babylonjs/Misc/observable';
+    import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
+    import { Scene } from 'babylonjs/scene';
+    interface IMeshPickerComponentProps {
+        globalState: GlobalState;
+        target: any;
+        property: string;
+        scene: Scene;
+        label: string;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    }
+    export class MeshPickerComponent extends React.Component<IMeshPickerComponentProps> {
+        constructor(props: IMeshPickerComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/particleSystems/meshEmitterGridComponent" {
+    import * as React from "react";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { GlobalState } from "babylonjs-inspector/components/globalState";
+    import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
+    import { LockObject } from "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/lockObject";
+    import { MeshParticleEmitter } from 'babylonjs/Particles/EmitterTypes/meshParticleEmitter';
+    import { Scene } from 'babylonjs/scene';
+    interface IMeshEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: MeshParticleEmitter;
+        scene: Scene;
+        lockObject: LockObject;
+        onSelectionChangedObservable?: Observable<any>;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    }
+    export class MeshEmitterGridComponent extends React.Component<IMeshEmitterGridComponentProps> {
+        constructor(props: IMeshEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
 declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/particleSystems/particleSystemPropertyGridComponent" {
     import * as React from "react";
     import { Observable } from "babylonjs/Misc/observable";
@@ -1766,6 +1924,8 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/par
     }
     export class ParticleSystemPropertyGridComponent extends React.Component<IParticleSystemPropertyGridComponentProps> {
         constructor(props: IParticleSystemPropertyGridComponentProps);
+        renderEmitter(): JSX.Element | null;
+        raiseOnPropertyChanged(property: string, newValue: any, previousValue: any): void;
         render(): JSX.Element;
     }
 }
@@ -2447,6 +2607,7 @@ declare module INSPECTOR {
         private _previousObject;
         private _previousProperty;
         reset(): void;
+        private _getIndirectData;
         record(event: PropertyChangedEvent): void;
         export(): void;
     }
@@ -2591,6 +2752,7 @@ declare module INSPECTOR {
         isSelected?: () => boolean;
         onSelect?: (value: boolean) => void;
         onValueChanged?: () => void;
+        replaySourceReplacement?: string;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
     }
     export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponentProps, {
@@ -2642,6 +2804,7 @@ declare module INSPECTOR {
         useEuler?: boolean;
         onChange?: (value: number) => void;
         onInput?: (value: number) => void;
+        replaySourceReplacement?: string;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
         decimalCount?: number;
     }
@@ -2755,6 +2918,7 @@ declare module INSPECTOR {
         step?: number;
         onChange?: (newvalue: BABYLON.Vector3) => void;
         useEuler?: boolean;
+        replaySourceReplacement?: string;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
     }
     export class Vector3LineComponent extends React.Component<IVector3LineComponentProps, {
@@ -2979,6 +3143,7 @@ declare module INSPECTOR {
         lockObject?: LockObject;
         onChange?: (newValue: number) => void;
         isInteger?: boolean;
+        replaySourceReplacement?: string;
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
         additionalClass?: string;
         step?: string;
@@ -3785,6 +3950,113 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    interface IBoxEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.BoxParticleEmitter;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class BoxEmitterGridComponent extends React.Component<IBoxEmitterGridComponentProps> {
+        constructor(props: IBoxEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IConeEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.ConeParticleEmitter;
+        onSelectionChangedObservable?: BABYLON.Observable<any>;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class ConeEmitterGridComponent extends React.Component<IConeEmitterGridComponentProps> {
+        constructor(props: IConeEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface ICylinderEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.CylinderParticleEmitter;
+        lockObject: LockObject;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class CylinderEmitterGridComponent extends React.Component<ICylinderEmitterGridComponentProps> {
+        constructor(props: ICylinderEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IHemisphericEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.HemisphericParticleEmitter;
+        lockObject: LockObject;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class HemisphericEmitterGridComponent extends React.Component<IHemisphericEmitterGridComponentProps> {
+        constructor(props: IHemisphericEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IPointEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.PointParticleEmitter;
+        lockObject: LockObject;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class PointEmitterGridComponent extends React.Component<IPointEmitterGridComponentProps> {
+        constructor(props: IPointEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface ISphereEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.SphereParticleEmitter;
+        lockObject: LockObject;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class SphereEmitterGridComponent extends React.Component<ISphereEmitterGridComponentProps> {
+        constructor(props: ISphereEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IMeshPickerComponentProps {
+        globalState: GlobalState;
+        target: any;
+        property: string;
+        scene: BABYLON.Scene;
+        label: string;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class MeshPickerComponent extends React.Component<IMeshPickerComponentProps> {
+        constructor(props: IMeshPickerComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IMeshEmitterGridComponentProps {
+        globalState: GlobalState;
+        emitter: BABYLON.MeshParticleEmitter;
+        scene: BABYLON.Scene;
+        lockObject: LockObject;
+        onSelectionChangedObservable?: BABYLON.Observable<any>;
+        replaySourceReplacement?: string;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class MeshEmitterGridComponent extends React.Component<IMeshEmitterGridComponentProps> {
+        constructor(props: IMeshEmitterGridComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     interface IParticleSystemPropertyGridComponentProps {
         globalState: GlobalState;
         system: BABYLON.IParticleSystem;
@@ -3794,6 +4066,8 @@ declare module INSPECTOR {
     }
     export class ParticleSystemPropertyGridComponent extends React.Component<IParticleSystemPropertyGridComponentProps> {
         constructor(props: IParticleSystemPropertyGridComponentProps);
+        renderEmitter(): JSX.Element | null;
+        raiseOnPropertyChanged(property: string, newValue: any, previousValue: any): void;
         render(): JSX.Element;
     }
 }

File diff suppressed because it is too large
+ 2 - 2
dist/preview release/nodeEditor/babylon.nodeEditor.js


File diff suppressed because it is too large
+ 30 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map


+ 1 - 1
dist/preview release/packagesSizeBaseLine.json

@@ -1 +1 @@
-{"thinEngineOnly":113745,"engineOnly":150348,"sceneOnly":506060,"minGridMaterial":636921,"minStandardMaterial":777051}
+{"thinEngineOnly":113745,"engineOnly":150348,"sceneOnly":506060,"minGridMaterial":636930,"minStandardMaterial":777060}

+ 13 - 12
dist/preview release/viewer/babylon.module.d.ts

@@ -13137,6 +13137,7 @@ declare module "babylonjs/Particles/EmitterTypes/meshParticleEmitter" {
     import { Effect } from "babylonjs/Materials/effect";
     import { Particle } from "babylonjs/Particles/particle";
     import { IParticleEmitterType } from "babylonjs/Particles/EmitterTypes/IParticleEmitterType";
+    import { Nullable } from "babylonjs/types";
     import { Scene } from "babylonjs/scene";
     import { AbstractMesh } from "babylonjs/Meshes/abstractMesh";
     /**
@@ -13144,12 +13145,11 @@ declare module "babylonjs/Particles/EmitterTypes/meshParticleEmitter" {
      * It emits the particles randomly between 2 given directions.
      */
     export class MeshParticleEmitter implements IParticleEmitterType {
-        /** Defines the mesh to use as source */
-        mesh?: AbstractMesh | undefined;
         private _indices;
         private _positions;
         private _normals;
         private _storedNormal;
+        private _mesh;
         /**
          * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
          */
@@ -13162,13 +13162,14 @@ declare module "babylonjs/Particles/EmitterTypes/meshParticleEmitter" {
          * Gets or sets a boolean indicating that particle directions must be built from mesh face normals
          */
         useMeshNormalsForDirection: boolean;
+        /** Defines the mesh to use as source */
+        get mesh(): Nullable<AbstractMesh>;
+        set mesh(value: Nullable<AbstractMesh>);
         /**
          * Creates a new instance MeshParticleEmitter
          * @param mesh defines the mesh to use as source
          */
-        constructor(
-        /** Defines the mesh to use as source */
-        mesh?: AbstractMesh | undefined);
+        constructor(mesh?: Nullable<AbstractMesh>);
         /**
          * Called by the particle System when the direction is computed for the created particle.
          * @param worldMatrix is the world matrix of the particle system
@@ -25559,7 +25560,7 @@ declare module "babylonjs/Meshes/mesh" {
         /** @hidden */
         _processInstancedBuffers(visibleInstances: InstancedMesh[], renderSelf: boolean): void;
         /** @hidden */
-        _processRendering(subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
+        _processRendering(renderingMesh: AbstractMesh, subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
         /** @hidden */
         _rebuild(): void;
         /** @hidden */
@@ -86293,12 +86294,11 @@ declare module BABYLON {
      * It emits the particles randomly between 2 given directions.
      */
     export class MeshParticleEmitter implements IParticleEmitterType {
-        /** Defines the mesh to use as source */
-        mesh?: AbstractMesh | undefined;
         private _indices;
         private _positions;
         private _normals;
         private _storedNormal;
+        private _mesh;
         /**
          * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
          */
@@ -86311,13 +86311,14 @@ declare module BABYLON {
          * Gets or sets a boolean indicating that particle directions must be built from mesh face normals
          */
         useMeshNormalsForDirection: boolean;
+        /** Defines the mesh to use as source */
+        get mesh(): Nullable<AbstractMesh>;
+        set mesh(value: Nullable<AbstractMesh>);
         /**
          * Creates a new instance MeshParticleEmitter
          * @param mesh defines the mesh to use as source
          */
-        constructor(
-        /** Defines the mesh to use as source */
-        mesh?: AbstractMesh | undefined);
+        constructor(mesh?: Nullable<AbstractMesh>);
         /**
          * Called by the particle System when the direction is computed for the created particle.
          * @param worldMatrix is the world matrix of the particle system
@@ -98266,7 +98267,7 @@ declare module BABYLON {
         /** @hidden */
         _processInstancedBuffers(visibleInstances: InstancedMesh[], renderSelf: boolean): void;
         /** @hidden */
-        _processRendering(subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
+        _processRendering(renderingMesh: AbstractMesh, subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean, onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh;
         /** @hidden */
         _rebuild(): void;
         /** @hidden */

File diff suppressed because it is too large
+ 15 - 15
dist/preview release/viewer/babylon.viewer.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/viewer/babylon.viewer.max.js


+ 2 - 0
dist/preview release/what's new.md

@@ -33,5 +33,7 @@
 
 - Fix infinite loop in `GlowLayer.unReferenceMeshFromUsingItsOwnMaterial` ([Popov72](https://github.com/Popov72)
 - `QuadraticErrorSimplification` was not exported ([RaananW](https://github.com/Raananw)
+- Fix NME Frames bug where collapsing and moving a frame removed the nodes inside ([Kyle Belfort](https://github.com/belfortk)
+
 
 ## Breaking changes

+ 2 - 1
inspector/src/components/actionTabs/lines/checkBoxLineComponent.tsx

@@ -9,6 +9,7 @@ export interface ICheckBoxLineComponentProps {
     isSelected?: () => boolean;
     onSelect?: (value: boolean) => void;
     onValueChanged?: () => void;
+    replaySourceReplacement?: string;
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
 }
 
@@ -52,7 +53,7 @@ export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponen
         } else {
             if (this.props.onPropertyChangedObservable) {
                 this.props.onPropertyChangedObservable.notifyObservers({
-                    object: this.props.target,
+                    object: this.props.replaySourceReplacement ?? this.props.target,
                     property: this.props.propertyName!,
                     value: !this.state.isSelected,
                     initialValue: this.state.isSelected

+ 2 - 1
inspector/src/components/actionTabs/lines/floatLineComponent.tsx

@@ -13,6 +13,7 @@ interface IFloatLineComponentProps {
     lockObject?: LockObject;
     onChange?: (newValue: number) => void;
     isInteger?: boolean;
+    replaySourceReplacement?: string;
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
     additionalClass?: string;
     step?: string,
@@ -61,7 +62,7 @@ export class FloatLineComponent extends React.Component<IFloatLineComponentProps
             return;
         }
         this.props.onPropertyChangedObservable.notifyObservers({
-            object: this.props.target,
+            object: this.props.replaySourceReplacement ?? this.props.target,
             property: this.props.propertyName,
             value: newValue,
             initialValue: previousValue

+ 85 - 0
inspector/src/components/actionTabs/lines/meshPickerComponent.tsx

@@ -0,0 +1,85 @@
+import * as React from "react";
+import { GlobalState } from '../../globalState';
+import { Observable } from 'babylonjs/Misc/observable';
+import { PropertyChangedEvent } from '../../propertyChangedEvent';
+import { Scene } from 'babylonjs/scene';
+import { OptionsLineComponent } from './optionsLineComponent';
+import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
+
+
+interface IMeshPickerComponentProps {
+    globalState: GlobalState;
+    target: any,
+    property: string,
+    scene: Scene,
+    label: string,
+    replaySourceReplacement?: string,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class MeshPickerComponent extends React.Component<IMeshPickerComponentProps> {
+    constructor(props: IMeshPickerComponentProps) {
+        super(props);
+
+    }
+
+    render() {
+        var meshEmitters = this.props.scene.meshes.filter(m => !!m.name);
+        meshEmitters.sort((a, b) => a.name.localeCompare(b.name));
+
+        var emitterOptions = [
+            { label: "None", value: -1 },
+        ];
+
+        meshEmitters.sort((a, b) => a.name.localeCompare(b.name));
+
+        emitterOptions.push(...meshEmitters.map((v, i) => {
+            return {label: v.name, value: i}
+        }));           
+        return (
+            <>       
+              <OptionsLineComponent 
+                        label={this.props.label}
+                        options={emitterOptions} 
+                        target={this.props.target}
+                        propertyName={this.props.property}
+                        noDirectUpdate={true}
+                        onSelect={(value: number) => {
+                            const currentState = this.props.target[this.props.property];
+                            switch(value) {
+                                case -1:
+                                    this.props.target[this.props.property] = null;
+                                    break;
+                                default:
+                                    this.props.target[this.props.property] = meshEmitters[value];
+                            }
+
+                            if (this.props.onPropertyChangedObservable) {                   
+                                this.props.onPropertyChangedObservable.notifyObservers({
+                                    object: this.props.replaySourceReplacement ?? this.props.target,
+                                    property: this.props.property,
+                                    value: this.props.target[this.props.property],
+                                    initialValue: currentState
+                                });
+                            }
+
+                            this.forceUpdate();
+                        }}
+                        extractValue={() => {
+                            if (!this.props.target[this.props.property]) {
+                                return -1;
+                            }
+
+                            let meshIndex = meshEmitters.indexOf(this.props.target[this.props.property] as AbstractMesh)
+
+                            if (meshIndex > -1) {
+                                return meshIndex;
+                            }
+
+                            return -1;
+                        }}
+                />               
+            </>
+        );
+    }
+}

+ 3 - 2
inspector/src/components/actionTabs/lines/sliderLineComponent.tsx

@@ -13,7 +13,8 @@ interface ISliderLineComponentProps {
     directValue?: number;
     useEuler?: boolean;
     onChange?: (value: number) => void;
-    onInput?: (value: number) => void;
+    onInput?: (value: number) => void;    
+    replaySourceReplacement?: string;
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
     decimalCount?: number;
 }
@@ -67,7 +68,7 @@ export class SliderLineComponent extends React.Component<ISliderLineComponentPro
         if (this.props.target) {
             if (this.props.onPropertyChangedObservable) {
                 this.props.onPropertyChangedObservable.notifyObservers({
-                    object: this.props.target,
+                    object: this.props.replaySourceReplacement ?? this.props.target,
                     property: this.props.propertyName!,
                     value: newValue,
                     initialValue: this.state.value

+ 2 - 1
inspector/src/components/actionTabs/lines/vector3LineComponent.tsx

@@ -16,6 +16,7 @@ interface IVector3LineComponentProps {
     step?: number;
     onChange?: (newvalue: Vector3) => void;
     useEuler?: boolean,
+    replaySourceReplacement?: string,
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
 }
 
@@ -62,7 +63,7 @@ export class Vector3LineComponent extends React.Component<IVector3LineComponentP
             return;
         }
         this.props.onPropertyChangedObservable.notifyObservers({
-            object: this.props.target,
+            object: this.props.replaySourceReplacement ?? this.props.target,
             property: this.props.propertyName,
             value: this.state.value,
             initialValue: previousValue

+ 37 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/boxEmitterGridComponent.tsx

@@ -0,0 +1,37 @@
+import * as React from "react";
+
+import { Observable } from "babylonjs/Misc/observable";
+import { GlobalState } from '../../../../globalState';
+import { PropertyChangedEvent } from '../../../../propertyChangedEvent';
+import { BoxParticleEmitter } from 'babylonjs/Particles/EmitterTypes/boxParticleEmitter';
+import { Vector3LineComponent } from '../../../lines/vector3LineComponent';
+
+interface IBoxEmitterGridComponentProps {
+    globalState: GlobalState;
+    emitter: BoxParticleEmitter,
+    replaySourceReplacement?: string,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class BoxEmitterGridComponent extends React.Component<IBoxEmitterGridComponentProps> {
+    constructor(props: IBoxEmitterGridComponentProps) {
+        super(props);
+
+    }
+
+    render() {
+        let emitter = this.props.emitter;
+        return (
+            <>
+                <Vector3LineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Direction 1" target={emitter} propertyName="direction1"
+                        onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <Vector3LineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Direction 2" target={emitter} propertyName="direction2"
+                        onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <Vector3LineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Min emit box" target={emitter} propertyName="minEmitBox"
+                        onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <Vector3LineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Max emit box" target={emitter} propertyName="maxEmitBox"
+                        onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+            </>
+        );
+    }
+}

+ 39 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/coneEmitterGridComponent.tsx

@@ -0,0 +1,39 @@
+import * as React from "react";
+
+import { Observable } from "babylonjs/Misc/observable";
+import { GlobalState } from '../../../../globalState';
+import { PropertyChangedEvent } from '../../../../propertyChangedEvent';
+import { ConeParticleEmitter } from 'babylonjs/Particles/EmitterTypes/coneParticleEmitter';
+import { SliderLineComponent } from '../../../lines/sliderLineComponent';
+import { CheckBoxLineComponent } from '../../../lines/checkBoxLineComponent';
+
+interface IConeEmitterGridComponentProps {
+    globalState: GlobalState;
+    emitter: ConeParticleEmitter,
+    onSelectionChangedObservable?: Observable<any>,
+    replaySourceReplacement?: string,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class ConeEmitterGridComponent extends React.Component<IConeEmitterGridComponentProps> {
+    constructor(props: IConeEmitterGridComponentProps) {
+        super(props);
+
+    }
+
+    render() {
+        let emitter = this.props.emitter;
+        return (
+            <>
+                <SliderLineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Radius range" target={emitter} propertyName="radiusRange" minimum={0} maximum={1} step={0.01} 
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <SliderLineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Height range" target={emitter} propertyName="heightRange" minimum={0} maximum={1} step={0.01} 
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <CheckBoxLineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Emit from spawn point only" target={emitter} propertyName="emitFromSpawnPointOnly" 
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />                    
+                <SliderLineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Direction randomizer" target={emitter} propertyName="directionRandomizer" minimum={0} maximum={1} step={0.01} 
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+            </>
+        );
+    }
+}

+ 38 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/cylinderEmitterGridComponent.tsx

@@ -0,0 +1,38 @@
+import * as React from "react";
+
+import { Observable } from "babylonjs/Misc/observable";
+import { GlobalState } from '../../../../globalState';
+import { PropertyChangedEvent } from '../../../../propertyChangedEvent';
+import { SliderLineComponent } from '../../../lines/sliderLineComponent';
+import { CylinderParticleEmitter } from 'babylonjs/Particles/EmitterTypes/cylinderParticleEmitter';
+import { FloatLineComponent } from '../../../lines/floatLineComponent';
+import { LockObject } from '../lockObject';
+
+interface ICylinderEmitterGridComponentProps {
+    globalState: GlobalState;
+    emitter: CylinderParticleEmitter,
+    lockObject: LockObject,
+    replaySourceReplacement?: string,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class CylinderEmitterGridComponent extends React.Component<ICylinderEmitterGridComponentProps> {
+    constructor(props: ICylinderEmitterGridComponentProps) {
+        super(props);
+
+    }
+
+    render() {
+        let emitter = this.props.emitter;
+        return (
+            <>                    
+                <FloatLineComponent replaySourceReplacement={this.props.replaySourceReplacement} lockObject={this.props.lockObject} label="Radius" target={emitter} propertyName="radius" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <FloatLineComponent replaySourceReplacement={this.props.replaySourceReplacement} lockObject={this.props.lockObject} label="Height" target={emitter} propertyName="height" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <SliderLineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Radius range" target={emitter} propertyName="radiusRange" minimum={0} maximum={1} step={0.01} 
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <SliderLineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Direction randomizer" target={emitter} propertyName="directionRandomizer" minimum={0} maximum={1} step={0.01} 
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+            </>
+        );
+    }
+}

+ 37 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/hemisphericEmitterGridComponent.tsx

@@ -0,0 +1,37 @@
+import * as React from "react";
+
+import { Observable } from "babylonjs/Misc/observable";
+import { GlobalState } from '../../../../globalState';
+import { PropertyChangedEvent } from '../../../../propertyChangedEvent';
+import { SliderLineComponent } from '../../../lines/sliderLineComponent';
+import { FloatLineComponent } from '../../../lines/floatLineComponent';
+import { LockObject } from '../lockObject';
+import { HemisphericParticleEmitter } from 'babylonjs/Particles/EmitterTypes/hemisphericParticleEmitter';
+
+interface IHemisphericEmitterGridComponentProps {
+    globalState: GlobalState;
+    emitter: HemisphericParticleEmitter,
+    lockObject: LockObject,    
+    replaySourceReplacement?: string,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class HemisphericEmitterGridComponent extends React.Component<IHemisphericEmitterGridComponentProps> {
+    constructor(props: IHemisphericEmitterGridComponentProps) {
+        super(props);
+
+    }
+
+    render() {
+        let emitter = this.props.emitter;
+        return (
+            <>                    
+                <FloatLineComponent replaySourceReplacement={this.props.replaySourceReplacement} lockObject={this.props.lockObject} label="Radius" target={emitter} propertyName="radius" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <SliderLineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Radius range" target={emitter} propertyName="radiusRange" minimum={0} maximum={1} step={0.01} 
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <SliderLineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Direction randomizer" target={emitter} propertyName="directionRandomizer" minimum={0} maximum={1} step={0.01} 
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+            </>
+        );
+    }
+}

+ 52 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/meshEmitterGridComponent.tsx

@@ -0,0 +1,52 @@
+import * as React from "react";
+
+import { Observable } from "babylonjs/Misc/observable";
+import { GlobalState } from '../../../../globalState';
+import { PropertyChangedEvent } from '../../../../propertyChangedEvent';
+import { LockObject } from '../lockObject';
+import { Vector3LineComponent } from '../../../lines/vector3LineComponent';
+import { MeshParticleEmitter } from 'babylonjs/Particles/EmitterTypes/meshParticleEmitter';
+import { CheckBoxLineComponent } from '../../../lines/checkBoxLineComponent';
+import { MeshPickerComponent } from '../../../lines/meshPickerComponent';
+import { Scene } from 'babylonjs/scene';
+
+interface IMeshEmitterGridComponentProps {
+    globalState: GlobalState;
+    emitter: MeshParticleEmitter,
+    scene: Scene,
+    lockObject: LockObject,
+    onSelectionChangedObservable?: Observable<any>,
+    replaySourceReplacement?: string,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class MeshEmitterGridComponent extends React.Component<IMeshEmitterGridComponentProps> {
+    constructor(props: IMeshEmitterGridComponentProps) {
+        super(props);
+
+    }
+
+    render() {
+        let emitter = this.props.emitter;    
+
+        return (
+            <>        
+                <MeshPickerComponent replaySourceReplacement={this.props.replaySourceReplacement} globalState={this.props.globalState} label="Source" scene={this.props.scene} 
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable}
+                    target={this.props.emitter} property="mesh"/>       
+                {
+                    !emitter.useMeshNormalsForDirection &&
+                    <Vector3LineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Direction 1" target={emitter} propertyName="direction1"
+                        onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                }
+                {
+                    !emitter.useMeshNormalsForDirection &&
+                    <Vector3LineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Direction 2" target={emitter} propertyName="direction2"
+                        onPropertyChangedObservable={this.props.onPropertyChangedObservable} />      
+                }
+                <CheckBoxLineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Use normals for direction" target={emitter} propertyName="useMeshNormalsForDirection" 
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />                                    
+            </>
+        );
+    }
+}

+ 160 - 17
inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/particleSystemPropertyGridComponent.tsx

@@ -24,6 +24,16 @@ import { CylinderParticleEmitter } from 'babylonjs/Particles/EmitterTypes/cylind
 import { HemisphericParticleEmitter } from 'babylonjs/Particles/EmitterTypes/hemisphericParticleEmitter';
 import { PointParticleEmitter } from 'babylonjs/Particles/EmitterTypes/pointParticleEmitter';
 import { SphereParticleEmitter } from 'babylonjs/Particles/EmitterTypes/sphereParticleEmitter';
+import { BoxEmitterGridComponent } from './boxEmitterGridComponent';
+import { ConeEmitterGridComponent } from './coneEmitterGridComponent';
+import { CylinderEmitterGridComponent } from './cylinderEmitterGridComponent';
+import { HemisphericEmitterGridComponent } from './hemisphericEmitterGridComponent';
+import { PointEmitterGridComponent } from './pointEmitterGridComponent';
+import { SphereEmitterGridComponent } from './sphereEmitterGridComponent';
+import { Vector3 } from 'babylonjs/Maths/math.vector';
+import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
+import { MeshParticleEmitter } from 'babylonjs/Particles/EmitterTypes/meshParticleEmitter';
+import { MeshEmitterGridComponent } from './meshEmitterGridComponent';
 
 interface IParticleSystemPropertyGridComponentProps {
     globalState: GlobalState;
@@ -38,6 +48,64 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
         super(props);
     }
 
+    renderEmitter() {
+        const system = this.props.system;
+        const replaySource = "particlesystem.particleEmitterType";
+        switch(system.particleEmitterType?.getClassName()) {
+            case "BoxParticleEmitter":
+                return (
+                    <BoxEmitterGridComponent replaySourceReplacement={replaySource}
+                        globalState={this.props.globalState} emitter={system.particleEmitterType as BoxParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
+                );
+            case "ConeParticleEmitter":
+                return (
+                    <ConeEmitterGridComponent replaySourceReplacement={replaySource}
+                        globalState={this.props.globalState} emitter={system.particleEmitterType as ConeParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
+                );
+            case "CylinderParticleEmitter":
+                return (
+                    <CylinderEmitterGridComponent replaySourceReplacement={replaySource}
+                        lockObject={this.props.lockObject} globalState={this.props.globalState} emitter={system.particleEmitterType as CylinderParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
+                );        
+            case "HemisphericParticleEmitter":
+                return (
+                    <HemisphericEmitterGridComponent replaySourceReplacement={replaySource}
+                        lockObject={this.props.lockObject} globalState={this.props.globalState} emitter={system.particleEmitterType as HemisphericParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
+                );  
+            case "MeshParticleEmitter":
+                return (
+                    <MeshEmitterGridComponent replaySourceReplacement={replaySource} 
+                    lockObject={this.props.lockObject} scene={system.getScene()} globalState={this.props.globalState} emitter={system.particleEmitterType as MeshParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
+                );                 
+            case "PointParticleEmitter":
+                return (
+                    <PointEmitterGridComponent replaySourceReplacement={replaySource}
+                        lockObject={this.props.lockObject} globalState={this.props.globalState} emitter={system.particleEmitterType as PointParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
+                );  
+            case "SphereParticleEmitter":
+                return (
+                    <SphereEmitterGridComponent replaySourceReplacement={replaySource}
+                        lockObject={this.props.lockObject} globalState={this.props.globalState} emitter={system.particleEmitterType as SphereParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
+                );                                                                                                       
+        }
+
+        return null;
+    }
+
+    raiseOnPropertyChanged(property: string, newValue: any, previousValue: any) {
+        if (!this.props.onPropertyChangedObservable) {
+            return;
+        }
+
+        const system = this.props.system;
+        this.props.onPropertyChangedObservable.notifyObservers({
+            object: system,
+            property: property,
+            value: newValue,
+            initialValue: previousValue
+        });
+    }
+
     render() {
         const system = this.props.system;
 
@@ -54,10 +122,25 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
             { label: "Cone", value: 1 },
             { label: "Cylinder", value: 2 },
             { label: "Hemispheric", value: 3 },
-            { label: "Point", value: 4 },
-            { label: "Sphere", value: 5 },
+            { label: "Mesh", value: 4 },
+            { label: "Point", value: 5 },
+            { label: "Sphere", value: 6 },
         ];
 
+
+        var meshEmitters = this.props.system.getScene().meshes.filter(m => !!m.name);
+
+        var emitterOptions = [
+            { label: "None", value: -1 },
+            { label: "Vector3", value: 0 }
+        ];
+
+        meshEmitters.sort((a, b) => a.name.localeCompare(b.name));
+
+        emitterOptions.push(...meshEmitters.map((v, i) => {
+            return {label: v.name, value: i + 1}
+        }));
+
         return (
             <div className="pane">
                 <CustomPropertyGridComponent globalState={this.props.globalState} target={system}
@@ -66,6 +149,7 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
                 <LineContainerComponent globalState={this.props.globalState} title="GENERAL">
                     <TextLineComponent label="ID" value={system.id} />
                     <TextLineComponent label="Class" value={system.getClassName()} />  
+                    <TextLineComponent label="Capacity" value={system.getCapacity().toString()} />  
                     <TextureLinkLineComponent label="Texture" texture={system.particleTexture} onSelectionChangedObservable={this.props.onSelectionChangedObservable}/>
                     <OptionsLineComponent label="Blend mode" options={blendModeOptions} target={system} propertyName="blendMode" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Vector3LineComponent label="Gravity" target={system} propertyName="gravity"
@@ -83,7 +167,56 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
                         }
                     }} />
                 </LineContainerComponent>
-                <LineContainerComponent globalState={this.props.globalState} title="Emitter">
+                <LineContainerComponent globalState={this.props.globalState} title="EMITTER">
+                <OptionsLineComponent 
+                        label="Emitter" 
+                        options={emitterOptions} 
+                        target={system}
+                        propertyName="emitter"
+                        noDirectUpdate={true}
+                        onSelect={(value: number) => {
+                            switch(value) {
+                                case -1:
+                                    this.raiseOnPropertyChanged("emitter", null, system.emitter);
+                                    system.emitter = null;                                    
+                                    break;
+                                case 0:
+                                    this.raiseOnPropertyChanged("emitter", Vector3.Zero(), system.emitter);
+                                    system.emitter = Vector3.Zero();
+                                    break;
+                                default:
+                                    
+                                    this.raiseOnPropertyChanged("emitter", meshEmitters[value - 1], system.emitter);
+                                    system.emitter = meshEmitters[value - 1];
+                            }
+                            this.forceUpdate();
+                        }}
+                        extractValue={() => {
+                            if (!system.emitter) {
+                                return -1;
+                            }
+
+                            if ((system.emitter as Vector3).x !== undefined) {
+                                return 0;
+                            }
+
+                            let meshIndex = meshEmitters.indexOf(system.emitter as AbstractMesh)
+
+                            if (meshIndex > -1) {
+                                return meshIndex + 1;
+                            }
+
+                            return -1;
+                        }}
+                        />   
+                    {
+                        system.emitter && ((system.emitter as Vector3).x === undefined) &&
+                        <TextLineComponent label="Link to emitter" value={(system.emitter as AbstractMesh).name} onLink={() => this.props.globalState.onSelectionChangedObservable.notifyObservers(system.emitter)}/>
+                    }                  
+                    {
+                        system.emitter && ((system.emitter as Vector3).x !== undefined) &&
+                        <Vector3LineComponent label="Position" target={system} propertyName="emitter" onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
+                    }                                                     
                     <OptionsLineComponent 
                         label="Type" 
                         options={particleEmitterTypeOptions} 
@@ -91,6 +224,7 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
                         propertyName="particleEmitterType"
                         noDirectUpdate={true}
                         onSelect={(value: number) => {
+                            const currentType = system.particleEmitterType;
                             switch(value) {
                                 case 0:
                                     system.particleEmitterType = new BoxParticleEmitter();
@@ -109,13 +243,19 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
                                     break;
                                     
                                 case 4:
-                                    system.particleEmitterType = new PointParticleEmitter();
+                                    system.particleEmitterType = new MeshParticleEmitter();
                                     break;   
 
                                 case 5:
+                                    system.particleEmitterType = new PointParticleEmitter();
+                                    break;   
+
+                                case 6:
                                     system.particleEmitterType = new SphereParticleEmitter();
                                     break;
                             }
+                            this.raiseOnPropertyChanged("particleEmitterType", system.particleEmitterType, currentType)
+                            this.forceUpdate();
                         }}
                         extractValue={() => {
                             switch(system.particleEmitterType?.getClassName()) {
@@ -126,18 +266,26 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
                                 case "CylinderParticleEmitter":
                                     return 2;        
                                 case "HemisphericParticleEmitter":
-                                    return 3;
-                                case "PointParticleEmitter":
+                                    return 3;       
+                                case "MeshParticleEmitter":
                                     return 4;
+                                case "PointParticleEmitter":
+                                    return 5;
                                 case "SphereParticleEmitter":
-                                    return 5;                                                                                                          
+                                    return 6;                                                                                                          
                             }
 
                             return 0;
-                        }}
-                        onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-
-                </LineContainerComponent>
+                        }}/>
+                    {
+                        this.renderEmitter()
+                    }
+                </LineContainerComponent>       
+                <LineContainerComponent globalState={this.props.globalState} title="EMISSION">
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Rate" target={system} propertyName="emitRate" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Min emit power" target={system} propertyName="minEmitPower" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    <FloatLineComponent lockObject={this.props.lockObject} label="Max emit power" target={system} propertyName="maxEmitPower" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                </LineContainerComponent>  
                 <LineContainerComponent globalState={this.props.globalState} title="SIZE">
                     <FloatLineComponent lockObject={this.props.lockObject} label="Min size" target={system} propertyName="minSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Max size" target={system} propertyName="maxSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
@@ -149,12 +297,7 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
                 <LineContainerComponent globalState={this.props.globalState} title="LIFETIME">
                     <FloatLineComponent lockObject={this.props.lockObject} label="Min lifetime" target={system} propertyName="minLifeTime" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Max lifetime" target={system} propertyName="maxLifeTime" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                </LineContainerComponent>           
-                <LineContainerComponent globalState={this.props.globalState} title="EMISSION">
-                    <FloatLineComponent lockObject={this.props.lockObject} label="Rate" target={system} propertyName="emitRate" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent lockObject={this.props.lockObject} label="Min emit power" target={system} propertyName="minEmitPower" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <FloatLineComponent lockObject={this.props.lockObject} label="Max emit power" target={system} propertyName="maxEmitPower" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                </LineContainerComponent>  
+                </LineContainerComponent>    
                 <LineContainerComponent globalState={this.props.globalState} title="COLORS">
                     <Color4LineComponent label="Color 1" target={system} propertyName="color1" 
                         onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 35 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/pointEmitterGridComponent.tsx

@@ -0,0 +1,35 @@
+import * as React from "react";
+
+import { Observable } from "babylonjs/Misc/observable";
+import { GlobalState } from '../../../../globalState';
+import { PropertyChangedEvent } from '../../../../propertyChangedEvent';
+import { LockObject } from '../lockObject';
+import { PointParticleEmitter } from 'babylonjs/Particles/EmitterTypes/pointParticleEmitter';
+import { Vector3LineComponent } from '../../../lines/vector3LineComponent';
+
+interface IPointEmitterGridComponentProps {
+    globalState: GlobalState;
+    emitter: PointParticleEmitter,
+    lockObject: LockObject,
+    replaySourceReplacement?: string,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class PointEmitterGridComponent extends React.Component<IPointEmitterGridComponentProps> {
+    constructor(props: IPointEmitterGridComponentProps) {
+        super(props);
+
+    }
+
+    render() {
+        let emitter = this.props.emitter;
+        return (
+            <>                   
+                <Vector3LineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Direction 1" target={emitter} propertyName="direction1"
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <Vector3LineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Direction 2" target={emitter} propertyName="direction2"
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />                 
+            </>
+        );
+    }
+}

+ 37 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/sphereEmitterGridComponent.tsx

@@ -0,0 +1,37 @@
+import * as React from "react";
+
+import { Observable } from "babylonjs/Misc/observable";
+import { GlobalState } from '../../../../globalState';
+import { PropertyChangedEvent } from '../../../../propertyChangedEvent';
+import { LockObject } from '../lockObject';
+import { SphereParticleEmitter } from 'babylonjs/Particles/EmitterTypes/sphereParticleEmitter';
+import { FloatLineComponent } from '../../../lines/floatLineComponent';
+import { SliderLineComponent } from '../../../lines/sliderLineComponent';
+
+interface ISphereEmitterGridComponentProps {
+    globalState: GlobalState;
+    emitter: SphereParticleEmitter,
+    lockObject: LockObject,
+    replaySourceReplacement?: string,
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>
+}
+
+export class SphereEmitterGridComponent extends React.Component<ISphereEmitterGridComponentProps> {
+    constructor(props: ISphereEmitterGridComponentProps) {
+        super(props);
+
+    }
+
+    render() {
+        let emitter = this.props.emitter;
+        return (
+            <>                   
+                <FloatLineComponent replaySourceReplacement={this.props.replaySourceReplacement} lockObject={this.props.lockObject} label="Radius" target={emitter} propertyName="radius" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <SliderLineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Radius range" target={emitter} propertyName="radiusRange" minimum={0} maximum={1} step={0.01} 
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <SliderLineComponent replaySourceReplacement={this.props.replaySourceReplacement} label="Direction randomizer" target={emitter} propertyName="directionRandomizer" minimum={0} maximum={1} step={0.01} 
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />               
+            </>
+        );
+    }
+}

+ 33 - 19
inspector/src/components/replayRecorder.ts

@@ -12,6 +12,36 @@ export class ReplayRecorder {
         this._previousProperty = "";
     }
 
+    private _getIndirectData(data: any) {
+        if (!data.getClassName) {
+            return data;
+        }
+
+        let indirectData = data.getClassName().toLowerCase();
+
+        if (data.id) {
+            if (indirectData === "Scene") {
+                indirectData = `scene`;
+            } else if (indirectData.indexOf("camera") > -1) {
+                indirectData = `scene.getCameraByID("${data.id}")`;
+            } else if (indirectData.indexOf("mesh") > -1) {
+                indirectData = `scene.getMeshByID("${data.id}")`;
+            } else if (indirectData.indexOf("light") > -1) {
+                indirectData = `scene.getLightByID("${data.id}")`;
+            } else if (indirectData === "transformnode") {
+                indirectData = `scene.getTransformNodeByID("${data.id}")`;
+            } else if (indirectData === "skeleton") {
+                indirectData = `scene.getSkeletonById("${data.id}")`;
+            } else if (indirectData.indexOf("material") > -1) {
+                indirectData = `scene.getMaterialByID("${data.id}")`;
+            }
+        } else {
+            indirectData = "new BABYLON." + data.getClassName() + "()";
+        }
+
+        return indirectData;
+    }
+
     public record(event: PropertyChangedEvent) {
         if (!this._recordedCodeLines) {
             this._recordedCodeLines = [];
@@ -33,27 +63,11 @@ export class ReplayRecorder {
             value = `new BABYLON.Color4(${value.r}, ${value.g}, ${value.b}, ${value.a})`;
         } else if (value.b !== undefined) { // Color3
             value = `new BABYLON.Color3(${value.r}, ${value.g}, ${value.b})`;
+        } else if (value.getClassName) {
+            value = this._getIndirectData(value);
         }
 
-        let target = event.object.getClassName().toLowerCase();
-
-        if (event.object.id) {
-            if (target === "Scene") {
-                target = `scene`;
-            } else if (target.indexOf("camera") > -1) {
-                target = `scene.getCameraByID("${event.object.id}")`;
-            } else if (target.indexOf("mesh") > -1) {
-                target = `scene.getMeshByID("${event.object.id}")`;
-            } else if (target.indexOf("light") > -1) {
-                target = `scene.getLightByID("${event.object.id}")`;
-            } else if (target === "transformnode") {
-                target = `scene.getTransformNodeByID("${event.object.id}")`;
-            } else if (target === "skeleton") {
-                target = `scene.getSkeletonById("${event.object.id}")`;
-            } else if (target.indexOf("material") > -1) {
-                target = `scene.getMaterialByID("${event.object.id}")`;
-            }
-        }
+        let target = this._getIndirectData(event.object);
 
         this._recordedCodeLines.push(`${target}.${event.property} = ${value};`);
 

+ 22 - 0
nodeEditor/src/diagram/graphCanvas.scss

@@ -242,6 +242,10 @@
                     cursor: ew-resize;
                     
                 }
+
+                &.collapsed {
+                    cursor: pointer;
+                }
             }
 
             .top-right-corner-handle{
@@ -374,6 +378,24 @@
                     height: 12px;
                 }
             }
+            
+            &.collapsed{
+                .top-handle, .top-right-corner-handle, .right-handle, .bottom-right-corner-handle, .bottom-handle, .bottom-left-corner-handle, .left-handle, .top-left-corner-handle {
+                    cursor: default;
+                }
+
+                .right-handle, .bottom-handle, .top-right-corner-handle, .bottom-right-corner-handle{
+                    &::after{
+                        cursor: default;
+                    }
+                }
+
+                .left-handle, .top-handle, .top-left-corner-handle, .bottom-left-corner-handle{
+                    &::before{
+                        cursor: default;
+                    }
+                }
+            }
         }
 
         #graph-svg-container {

+ 32 - 3
nodeEditor/src/diagram/graphFrame.ts

@@ -78,7 +78,7 @@ export class GraphFrame {
         port.delegatedPort = localPort;
         this._controlledPorts.push(port);
     }
-   
+
     public set isCollapsed(value: boolean) {
         if (this._isCollapsed === value) {
             return;
@@ -135,7 +135,7 @@ export class GraphFrame {
                     } else {
                         this._createInputPort(port, node);
                     }
-                }               
+                }
             }
         } else {
             this.element.classList.remove("collapsed");
@@ -489,7 +489,7 @@ export class GraphFrame {
         this._ownerCanvas._frameIsMoving = true;
 
         this.move(this._ownerCanvas.getGridPosition(this.x), this._ownerCanvas.getGridPosition(this.y))
-    }    
+    }
 
     public move(newX: number, newY: number, align = true) {
         let oldX = this.x;
@@ -498,6 +498,11 @@ export class GraphFrame {
         this.x = newX;
         this.y = newY;
 
+        console.log("move():");
+        console.log("oldX: ", oldX);
+        console.log("oldY: ", oldY);
+        console.log("newX: ", newX);
+        console.log("newY: ", oldY);
         for (var selectedNode of this._nodes) {
             selectedNode.x += this.x - oldX;
             selectedNode.y += this.y - oldY;
@@ -587,6 +592,9 @@ export class GraphFrame {
     private _onRightHandlePointerDown = (evt: PointerEvent) => {
         // tslint:disable-next-line: no-this-assignment
         const _this = this;
+        if (_this.isCollapsed) {
+            return;
+        }
         this.initResizing(evt);
         _this._resizingDirection = ResizingDirection.Right;
         _this.mouseXLimit = evt.clientX - (_this.width - _this._minFrameWidth);
@@ -630,6 +638,9 @@ export class GraphFrame {
     private _onBottomHandlePointerDown = (evt: PointerEvent) => {
         // tslint:disable-next-line: no-this-assignment
         const _this = this;
+            if (_this.isCollapsed) {
+                return;
+            }
         _this.initResizing(evt);
         _this._resizingDirection = ResizingDirection.Bottom;
         _this._ownerCanvas.hostCanvas.addEventListener("pointermove", _this._onBottomHandlePointerMove);
@@ -670,6 +681,9 @@ export class GraphFrame {
     private _onLeftHandlePointerDown = (evt: PointerEvent) => {
         // tslint:disable-next-line: no-this-assignment
         const _this = this;
+        if (_this.isCollapsed) {
+                return;
+            }
         _this.initResizing(evt);
         _this._resizingDirection = ResizingDirection.Left;
         _this.mouseXLimit = evt.clientX + _this.width - _this._minFrameWidth;
@@ -714,6 +728,9 @@ export class GraphFrame {
     private _onTopHandlePointerDown = (evt: PointerEvent) => {
         // tslint:disable-next-line: no-this-assignment
         const _this = this;
+        if (_this.isCollapsed) {
+                return;
+            }
         _this.initResizing(evt);
         _this._resizingDirection = ResizingDirection.Top;
         _this._ownerCanvas.hostCanvas.addEventListener("pointerup", _this._onTopHandlePointerUp);
@@ -755,6 +772,9 @@ export class GraphFrame {
     private _onTopRightHandlePointerDown = (evt: PointerEvent) => {
         // tslint:disable-next-line: no-this-assignment
         const _this = this;
+        if (_this.isCollapsed) {
+                return;
+            }
         _this.initResizing(evt);
         _this._resizingDirection = ResizingDirection.TopRight;
         _this._ownerCanvas.hostCanvas.addEventListener("pointerup", _this._onTopRightHandlePointerUp);
@@ -813,6 +833,9 @@ export class GraphFrame {
     private _onBottomRightHandlePointerDown = (evt: PointerEvent) => {
         // tslint:disable-next-line: no-this-assignment
         const _this = this;
+        if (_this.isCollapsed) {
+                return;
+            }
         _this.initResizing(evt);
         _this._resizingDirection = ResizingDirection.BottomRight;
         _this._ownerCanvas.hostCanvas.addEventListener("pointerup", _this._onBottomRightHandlePointerUp);
@@ -870,6 +893,9 @@ export class GraphFrame {
     private _onBottomLeftHandlePointerDown = (evt: PointerEvent) => {
         // tslint:disable-next-line: no-this-assignment
         const _this = this;
+        if (_this.isCollapsed) {
+                return;
+            }
         _this.initResizing(evt);
         _this._resizingDirection = ResizingDirection.BottomLeft;
         _this.mouseXLimit = evt.clientX + _this.width - _this._minFrameWidth;
@@ -929,6 +955,9 @@ export class GraphFrame {
     private _onTopLeftHandlePointerDown = (evt: PointerEvent) => {
         // tslint:disable-next-line: no-this-assignment
         const _this = this;
+        if (_this.isCollapsed) {
+                return;
+            }
         _this.initResizing(evt);
         _this._resizingDirection = ResizingDirection.TopLeft;
         _this.mouseXLimit = evt.clientX + _this.width - _this._minFrameWidth;

+ 5 - 5
src/Engines/nativeEngine.ts

@@ -72,9 +72,9 @@ interface INativeEngine {
     setFloat4(uniform: WebGLUniformLocation, x: number, y: number, z: number, w: number): void;
 
     createTexture(): WebGLTexture;
-    loadTexture(texture: WebGLTexture, buffer: ArrayBuffer | ArrayBufferView | Blob, mipMap: boolean, invertY: boolean): boolean;
-    loadEnvTexture(texture: WebGLTexture, data: Array<Array<ArrayBufferView>>): boolean;
-    loadCubeTexture(texture: WebGLTexture, data: Array<ArrayBufferView>, generateMipMaps: boolean): boolean;
+    loadTexture(texture: WebGLTexture, buffer: ArrayBuffer | ArrayBufferView | Blob, generateMips: boolean, invertY: boolean): boolean;
+    loadCubeTexture(texture: WebGLTexture, data: Array<ArrayBufferView>, generateMips: boolean): boolean;
+    loadCubeTextureWithMips(texture: WebGLTexture, data: Array<Array<ArrayBufferView>>): boolean;
     getTextureWidth(texture: WebGLTexture): number;
     getTextureHeight(texture: WebGLTexture): number;
     setTextureSampling(texture: WebGLTexture, filter: number): void; // filter is a NativeFilter.XXXX value.
@@ -83,7 +83,7 @@ interface INativeEngine {
     setTexture(uniform: WebGLUniformLocation, texture: Nullable<WebGLTexture>): void;
     deleteTexture(texture: Nullable<WebGLTexture>): void;
 
-    createFramebuffer(texture: WebGLTexture, width: number, height: number, format: number, samplingMode: number, generateStencilBuffer: boolean, generateDepthBuffer: boolean, generateMipMaps: boolean): WebGLFramebuffer;
+    createFramebuffer(texture: WebGLTexture, width: number, height: number, format: number, samplingMode: number, generateStencilBuffer: boolean, generateDepthBuffer: boolean, generateMips: boolean): WebGLFramebuffer;
     deleteFramebuffer(framebuffer: WebGLFramebuffer): void;
     bindFramebuffer(framebuffer: WebGLFramebuffer): void;
     unbindFramebuffer(framebuffer: WebGLFramebuffer): void;
@@ -1084,7 +1084,7 @@ export class NativeEngine extends Engine {
                 texture.getEngine().updateTextureSamplingMode(Texture.TRILINEAR_SAMPLINGMODE, texture);
                 texture._isRGBD = true;
                 texture.invertY = true;
-                if (!this._native.loadEnvTexture(texture._webGLTexture!, imageData)) {
+                if (!this._native.loadCubeTextureWithMips(texture._webGLTexture!, imageData)) {
                     throw new Error("Could not load a native cube texture.");
                 }
 

+ 2 - 3
src/Layers/effectLayer.ts

@@ -763,9 +763,8 @@ export abstract class EffectLayer {
             }
 
             // Draw
-            var world = effectiveMesh.getWorldMatrix();
-            renderingMesh._processRendering(subMesh, this._effectLayerMapGenerationEffect, material.fillMode, batch, hardwareInstancedRendering,
-                (isInstance, w) => this._effectLayerMapGenerationEffect.setMatrix("world", world));
+            renderingMesh._processRendering(effectiveMesh, subMesh, this._effectLayerMapGenerationEffect, material.fillMode, batch, hardwareInstancedRendering,
+                (isInstance, world) => this._effectLayerMapGenerationEffect.setMatrix("world", world));
         } else {
             // Need to reset refresh rate of the main map
             this._mainTexture.resetRefreshCounter();

+ 2 - 4
src/Lights/Shadows/shadowGenerator.ts

@@ -1087,10 +1087,8 @@ export class ShadowGenerator implements IShadowGenerator {
             this.onBeforeShadowMapRenderObservable.notifyObservers(this._effect);
 
             // Draw
-
-            var world = effectiveMesh.getWorldMatrix();
-            renderingMesh._processRendering(subMesh, this._effect, material.fillMode, batch, hardwareInstancedRendering,
-                (isInstance, w) => this._effect.setMatrix("world", world));
+            renderingMesh._processRendering(effectiveMesh, subMesh, this._effect, material.fillMode, batch, hardwareInstancedRendering,
+                (isInstance, world) => this._effect.setMatrix("world", world));
 
             if (this.forceBackFacesOnly) {
                 engine.setState(true, 0, false, false);

+ 4 - 4
src/Meshes/mesh.ts

@@ -1607,7 +1607,7 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
     }
 
     /** @hidden */
-    public _processRendering(subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean,
+    public _processRendering(renderingMesh: AbstractMesh, subMesh: SubMesh, effect: Effect, fillMode: number, batch: _InstancesBatch, hardwareInstancedRendering: boolean,
         onBeforeDraw: (isInstance: boolean, world: Matrix, effectiveMaterial?: Material) => void, effectiveMaterial?: Material): Mesh {
         var scene = this.getScene();
         var engine = scene.getEngine();
@@ -1619,7 +1619,7 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
             if (batch.renderSelf[subMesh._id]) {
                 // Draw
                 if (onBeforeDraw) {
-                    onBeforeDraw(false, this._effectiveMesh.getWorldMatrix(), effectiveMaterial);
+                    onBeforeDraw(false, renderingMesh._effectiveMesh.getWorldMatrix(), effectiveMaterial);
                 }
                 instanceCount++;
 
@@ -1807,12 +1807,12 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
 
         if (!this._effectiveMaterial.backFaceCulling && this._effectiveMaterial.separateCullingPass) {
             engine.setState(true, this._effectiveMaterial.zOffset, false, !reverse);
-            this._processRendering(subMesh, effect, fillMode, batch, hardwareInstancedRendering, this._onBeforeDraw, this._effectiveMaterial);
+            this._processRendering(this, subMesh, effect, fillMode, batch, hardwareInstancedRendering, this._onBeforeDraw, this._effectiveMaterial);
             engine.setState(true, this._effectiveMaterial.zOffset, false, reverse);
         }
 
         // Draw
-        this._processRendering(subMesh, effect, fillMode, batch, hardwareInstancedRendering, this._onBeforeDraw, this._effectiveMaterial);
+        this._processRendering(this, subMesh, effect, fillMode, batch, hardwareInstancedRendering, this._onBeforeDraw, this._effectiveMaterial);
 
         // Unbind
         this._effectiveMaterial.unbind();

+ 27 - 10
src/Particles/EmitterTypes/meshParticleEmitter.ts

@@ -17,6 +17,7 @@ export class MeshParticleEmitter implements IParticleEmitterType {
     private _positions: Nullable<FloatArray> = null;
     private _normals: Nullable<FloatArray> = null;
     private _storedNormal = Vector3.Zero();
+    private _mesh: Nullable<AbstractMesh> = null;
 
     /**
      * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
@@ -32,19 +33,35 @@ export class MeshParticleEmitter implements IParticleEmitterType {
      */
     public useMeshNormalsForDirection = true;
 
+    /** Defines the mesh to use as source */
+    public get mesh(): Nullable<AbstractMesh> {
+        return this._mesh;
+    }
+
+    public set mesh(value: Nullable<AbstractMesh>) {
+        if (this._mesh === value) {
+            return;
+        }
+
+        this._mesh = value;
+
+        if (value) {
+            this._indices = value.getIndices();
+            this._positions = value.getVerticesData(VertexBuffer.PositionKind);
+            this._normals = value.getVerticesData(VertexBuffer.NormalKind);
+        } else {
+            this._indices = null;
+            this._positions = null;
+            this._normals = null;
+        }
+    }
+
     /**
      * Creates a new instance MeshParticleEmitter
      * @param mesh defines the mesh to use as source
      */
-    constructor(
-        /** Defines the mesh to use as source */
-        public mesh?: AbstractMesh) {
-
-        if (mesh) {
-            this._indices = mesh.getIndices();
-            this._positions = mesh.getVerticesData(VertexBuffer.PositionKind);
-            this._normals = mesh.getVerticesData(VertexBuffer.NormalKind);
-        }
+    constructor(mesh: Nullable<AbstractMesh> = null) {
+        this.mesh = mesh;
     }
 
     /**
@@ -185,7 +202,7 @@ export class MeshParticleEmitter implements IParticleEmitterType {
         Vector3.FromArrayToRef(serializationObject.direction2, 0, this.direction2);
 
         if (serializationObject.meshId) {
-            this.mesh = scene.getLastMeshByID(serializationObject.meshId) || undefined;
+            this.mesh = scene.getLastMeshByID(serializationObject.meshId);
         }
 
         this.useMeshNormalsForDirection = serializationObject.useMeshNormalsForDirection;

+ 2 - 3
src/PostProcesses/volumetricLightScatteringPostProcess.ts

@@ -359,9 +359,8 @@ export class VolumetricLightScatteringPostProcess extends PostProcess {
                 }
 
                 // Draw
-                var world = effectiveMesh.getWorldMatrix();
-                renderingMesh._processRendering(subMesh, this._volumetricLightScatteringPass, Material.TriangleFillMode, batch, hardwareInstancedRendering,
-                    (isInstance, w) => effect.setMatrix("world", world));
+                renderingMesh._processRendering(effectiveMesh, subMesh, this._volumetricLightScatteringPass, Material.TriangleFillMode, batch, hardwareInstancedRendering,
+                    (isInstance, world) => effect.setMatrix("world", world));
             }
         };
 

+ 2 - 3
src/Rendering/depthRenderer.ts

@@ -148,9 +148,8 @@ export class DepthRenderer {
                 MaterialHelper.BindMorphTargetParameters(renderingMesh, this._effect);
 
                 // Draw
-                var world = effectiveMesh.getWorldMatrix();
-                renderingMesh._processRendering(subMesh, this._effect, material.fillMode, batch, hardwareInstancedRendering,
-                    (isInstance, w) => this._effect.setMatrix("world", world));
+                renderingMesh._processRendering(effectiveMesh, subMesh, this._effect, material.fillMode, batch, hardwareInstancedRendering,
+                    (isInstance, world) => this._effect.setMatrix("world", world));
             }
         };
 

+ 2 - 2
src/Rendering/geometryBufferRenderer.ts

@@ -485,8 +485,8 @@ export class GeometryBufferRenderer {
                 }
 
                 // Draw
-                renderingMesh._processRendering(subMesh, this._effect, material.fillMode, batch, hardwareInstancedRendering,
-                    (isInstance, w) => this._effect.setMatrix("world", world));
+                renderingMesh._processRendering(effectiveMesh, subMesh, this._effect, material.fillMode, batch, hardwareInstancedRendering,
+                    (isInstance, w) => this._effect.setMatrix("world", w));
             }
 
             // Velocity

+ 2 - 3
src/Rendering/outlineRenderer.ts

@@ -204,9 +204,8 @@ export class OutlineRenderer implements ISceneComponent {
         }
 
         engine.setZOffset(-this.zOffset);
-        var world = effectiveMesh.getWorldMatrix();
-        renderingMesh._processRendering(subMesh, this._effect, material.fillMode, batch, hardwareInstancedRendering,
-            (isInstance, w) => { this._effect.setMatrix("world", world); });
+        renderingMesh._processRendering(effectiveMesh, subMesh, this._effect, material.fillMode, batch, hardwareInstancedRendering,
+            (isInstance, world) => { this._effect.setMatrix("world", world); });
 
         engine.setZOffset(0);
     }