Browse Source

Associated with #8111 + Nightly

David Catuhe 5 years ago
parent
commit
5402fe0725
27 changed files with 1300 additions and 461 deletions
  1. 65 18
      dist/preview release/babylon.d.ts
  2. 1 1
      dist/preview release/babylon.js
  3. 264 91
      dist/preview release/babylon.max.js
  4. 1 1
      dist/preview release/babylon.max.js.map
  5. 131 37
      dist/preview release/babylon.module.d.ts
  6. 65 18
      dist/preview release/documentation.d.ts
  7. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.js
  8. 110 18
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  9. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  10. 5 0
      dist/preview release/inspector/babylon.inspector.d.ts
  11. 10 0
      dist/preview release/inspector/babylon.inspector.module.d.ts
  12. 51 51
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  13. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  14. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  15. 51 51
      dist/preview release/loaders/babylon.glTFFileLoader.js
  16. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  17. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  18. 51 51
      dist/preview release/loaders/babylonjs.loaders.js
  19. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  20. 2 2
      dist/preview release/loaders/babylonjs.loaders.min.js
  21. 131 37
      dist/preview release/viewer/babylon.module.d.ts
  22. 69 69
      dist/preview release/viewer/babylon.viewer.js
  23. 2 2
      dist/preview release/viewer/babylon.viewer.max.js
  24. 1 1
      inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/particleSystemPropertyGridComponent.tsx
  25. 111 0
      inspector/src/components/actionTabs/tabs/propertyGrids/sprites/spriteManagerPropertyGridComponent.tsx
  26. 69 3
      src/Sprites/sprite.ts
  27. 103 3
      src/Sprites/spriteManager.ts

+ 65 - 18
dist/preview release/babylon.d.ts

@@ -10258,13 +10258,25 @@ declare module BABYLON {
          * @param delay defines the start delay (in ms)
          * @param onAnimationEnd defines a callback to call when animation ends
          */
-        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
+        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd?: Nullable<() => void>): void;
         /** Stops current animation (if any) */
         stopAnimation(): void;
         /** @hidden */
         _animate(deltaTime: number): void;
         /** Release associated resources */
         dispose(): void;
+        /**
+         * Serializes the sprite to a JSON object
+         * @returns the JSON object
+         */
+        serialize(): any;
+        /**
+         * Parses a JSON object to create a new sprite
+         * @param parsedSprite The JSON object to parse
+         * @param manager defines the hosting manager
+         * @returns the new sprite
+         */
+        static Parse(parsedSprite: any, manager: SpriteManager): Sprite;
     }
 }
 declare module BABYLON {
@@ -10898,6 +10910,10 @@ declare module BABYLON {
     export class SpriteManager implements ISpriteManager {
         /** defines the manager's name */
         name: string;
+        /** Define the Url to load snippets */
+        static SnippetUrl: string;
+        /** Snippet ID if the manager was created from the snippet server */
+        snippetId: string;
         /** Gets the list of sprites */
         sprites: Sprite[];
         /** Gets or sets the rendering group id (0 by default) */
@@ -11021,6 +11037,28 @@ declare module BABYLON {
          * Release associated resources
          */
         dispose(): void;
+        /**
+         * Serializes the sprite manager to a JSON object
+         * @param serializeTexture defines if the texture must be serialized as well
+         * @returns the JSON object
+         */
+        serialize(serializeTexture?: boolean): any;
+        /**
+         * Parses a JSON object to create a new sprite manager.
+         * @param parsedManager The JSON object to parse
+         * @param scene The scene to create the sprite managerin
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the new sprite manager
+         */
+        static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager;
+        /**
+         * Creates a sprite manager from a snippet saved by the sprite editor
+         * @param snippetId defines the snippet to load
+         * @param scene defines the hosting scene
+         * @param rootUrl defines the root URL to use to load textures and relative dependencies
+         * @returns a promise that will resolve to the new sprite manager
+         */
+        static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl?: string): Promise<SpriteManager>;
     }
 }
 declare module BABYLON {
@@ -16125,6 +16163,13 @@ declare module BABYLON {
          */
         get sourceMesh(): Mesh;
         /**
+         * Creates a new InstancedMesh object from the mesh model.
+         * @see http://doc.babylonjs.com/how_to/how_to_use_instances
+         * @param name defines the name of the new instance
+         * @returns a new InstancedMesh
+         */
+        createInstance(name: string): InstancedMesh;
+        /**
          * Is this node ready to be used/rendered
          * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
          * @return {boolean} is it ready
@@ -32756,18 +32801,6 @@ declare module BABYLON {
          * @returns "BaseTexture"
          */
         getClassName(): string;
-        private _realTimeFiltering;
-        /**
-         * Enables realtime filtering on the texture.
-         */
-        get realTimeFiltering(): boolean;
-        set realTimeFiltering(b: boolean);
-        private _realTimeFilteringQuality;
-        /**
-         * Quality switch for realtime filtering
-         */
-        get realTimeFilteringQuality(): number;
-        set realTimeFilteringQuality(n: number);
         /**
          * Define the list of animation attached to the texture.
          */
@@ -37078,9 +37111,10 @@ declare module BABYLON {
         static MakeArray(obj: any, allowsNullUndefined?: boolean): Nullable<Array<any>>;
         /**
          * Gets the pointer prefix to use
+         * @param engine defines the engine we are finding the prefix for
          * @returns "pointer" if touch is enabled. Else returns "mouse"
          */
-        static GetPointerPrefix(): string;
+        static GetPointerPrefix(engine: Engine): string;
         /**
          * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
          * @param url define the url we are trying
@@ -54031,10 +54065,11 @@ declare module BABYLON {
          * @param uniformBuffer defines the Uniform buffer to fill in.
          * @param scene defines the scene the material belongs to.
          * @param engine defines the engine the material belongs to.
-         * @param isFrozen defines wether the material is frozen or not.
-         * @param lodBasedMicrosurface defines wether the material relies on lod based microsurface or not.
+         * @param isFrozen defines whether the material is frozen or not.
+         * @param lodBasedMicrosurface defines whether the material relies on lod based microsurface or not.
+         * @param realTimeFiltering defines whether the textures should be filtered on the fly.
          */
-        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean): void;
+        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean, realTimeFiltering: boolean): void;
         /**
          * Unbinds the material from the mesh.
          * @param activeEffect defines the effect that should be unbound from.
@@ -54866,6 +54901,18 @@ declare module BABYLON {
          * Force the shader to compute irradiance in the fragment shader in order to take bump in account.
          */
         protected _forceIrradianceInFragment: boolean;
+        private _realTimeFiltering;
+        /**
+         * Enables realtime filtering on the texture.
+         */
+        get realTimeFiltering(): boolean;
+        set realTimeFiltering(b: boolean);
+        private _realTimeFilteringQuality;
+        /**
+         * Quality switch for realtime filtering
+         */
+        get realTimeFilteringQuality(): number;
+        set realTimeFilteringQuality(n: number);
         /**
          * Force normal to face away from face.
          */
@@ -58427,7 +58474,7 @@ declare module BABYLON {
           * @param onFinished Callback when filtering is done
           * @return Promise called when prefiltering is done
           */
-        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown>;
+        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown> | undefined;
     }
 }
 declare module BABYLON {

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


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


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


+ 131 - 37
dist/preview release/babylon.module.d.ts

@@ -10316,7 +10316,7 @@ declare module "babylonjs/Sprites/sprite" {
     import { Vector3 } from "babylonjs/Maths/math.vector";
     import { Nullable } from "babylonjs/types";
     import { ActionManager } from "babylonjs/Actions/actionManager";
-    import { ISpriteManager } from "babylonjs/Sprites/spriteManager";
+    import { ISpriteManager, SpriteManager } from "babylonjs/Sprites/spriteManager";
     import { Color4 } from "babylonjs/Maths/math.color";
     import { Observable } from "babylonjs/Misc/observable";
     import { IAnimatable } from "babylonjs/Animations/animatable.interface";
@@ -10433,13 +10433,25 @@ declare module "babylonjs/Sprites/sprite" {
          * @param delay defines the start delay (in ms)
          * @param onAnimationEnd defines a callback to call when animation ends
          */
-        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
+        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd?: Nullable<() => void>): void;
         /** Stops current animation (if any) */
         stopAnimation(): void;
         /** @hidden */
         _animate(deltaTime: number): void;
         /** Release associated resources */
         dispose(): void;
+        /**
+         * Serializes the sprite to a JSON object
+         * @returns the JSON object
+         */
+        serialize(): any;
+        /**
+         * Parses a JSON object to create a new sprite
+         * @param parsedSprite The JSON object to parse
+         * @param manager defines the hosting manager
+         * @returns the new sprite
+         */
+        static Parse(parsedSprite: any, manager: SpriteManager): Sprite;
     }
 }
 declare module "babylonjs/Collisions/pickingInfo" {
@@ -11123,6 +11135,10 @@ declare module "babylonjs/Sprites/spriteManager" {
     export class SpriteManager implements ISpriteManager {
         /** defines the manager's name */
         name: string;
+        /** Define the Url to load snippets */
+        static SnippetUrl: string;
+        /** Snippet ID if the manager was created from the snippet server */
+        snippetId: string;
         /** Gets the list of sprites */
         sprites: Sprite[];
         /** Gets or sets the rendering group id (0 by default) */
@@ -11246,6 +11262,28 @@ declare module "babylonjs/Sprites/spriteManager" {
          * Release associated resources
          */
         dispose(): void;
+        /**
+         * Serializes the sprite manager to a JSON object
+         * @param serializeTexture defines if the texture must be serialized as well
+         * @returns the JSON object
+         */
+        serialize(serializeTexture?: boolean): any;
+        /**
+         * Parses a JSON object to create a new sprite manager.
+         * @param parsedManager The JSON object to parse
+         * @param scene The scene to create the sprite managerin
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the new sprite manager
+         */
+        static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager;
+        /**
+         * Creates a sprite manager from a snippet saved by the sprite editor
+         * @param snippetId defines the snippet to load
+         * @param scene defines the hosting scene
+         * @param rootUrl defines the root URL to use to load textures and relative dependencies
+         * @returns a promise that will resolve to the new sprite manager
+         */
+        static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl?: string): Promise<SpriteManager>;
     }
 }
 declare module "babylonjs/Misc/gradients" {
@@ -16544,6 +16582,13 @@ declare module "babylonjs/Meshes/instancedMesh" {
          */
         get sourceMesh(): Mesh;
         /**
+         * Creates a new InstancedMesh object from the mesh model.
+         * @see http://doc.babylonjs.com/how_to/how_to_use_instances
+         * @param name defines the name of the new instance
+         * @returns a new InstancedMesh
+         */
+        createInstance(name: string): InstancedMesh;
+        /**
          * Is this node ready to be used/rendered
          * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
          * @return {boolean} is it ready
@@ -33879,18 +33924,6 @@ declare module "babylonjs/Materials/Textures/baseTexture" {
          * @returns "BaseTexture"
          */
         getClassName(): string;
-        private _realTimeFiltering;
-        /**
-         * Enables realtime filtering on the texture.
-         */
-        get realTimeFiltering(): boolean;
-        set realTimeFiltering(b: boolean);
-        private _realTimeFilteringQuality;
-        /**
-         * Quality switch for realtime filtering
-         */
-        get realTimeFilteringQuality(): number;
-        set realTimeFilteringQuality(n: number);
         /**
          * Define the list of animation attached to the texture.
          */
@@ -38300,9 +38333,10 @@ declare module "babylonjs/Misc/tools" {
         static MakeArray(obj: any, allowsNullUndefined?: boolean): Nullable<Array<any>>;
         /**
          * Gets the pointer prefix to use
+         * @param engine defines the engine we are finding the prefix for
          * @returns "pointer" if touch is enabled. Else returns "mouse"
          */
-        static GetPointerPrefix(): string;
+        static GetPointerPrefix(engine: Engine): string;
         /**
          * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
          * @param url define the url we are trying
@@ -56374,10 +56408,11 @@ declare module "babylonjs/Materials/PBR/pbrSubSurfaceConfiguration" {
          * @param uniformBuffer defines the Uniform buffer to fill in.
          * @param scene defines the scene the material belongs to.
          * @param engine defines the engine the material belongs to.
-         * @param isFrozen defines wether the material is frozen or not.
-         * @param lodBasedMicrosurface defines wether the material relies on lod based microsurface or not.
+         * @param isFrozen defines whether the material is frozen or not.
+         * @param lodBasedMicrosurface defines whether the material relies on lod based microsurface or not.
+         * @param realTimeFiltering defines whether the textures should be filtered on the fly.
          */
-        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean): void;
+        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean, realTimeFiltering: boolean): void;
         /**
          * Unbinds the material from the mesh.
          * @param activeEffect defines the effect that should be unbound from.
@@ -57303,6 +57338,18 @@ declare module "babylonjs/Materials/PBR/pbrBaseMaterial" {
          * Force the shader to compute irradiance in the fragment shader in order to take bump in account.
          */
         protected _forceIrradianceInFragment: boolean;
+        private _realTimeFiltering;
+        /**
+         * Enables realtime filtering on the texture.
+         */
+        get realTimeFiltering(): boolean;
+        set realTimeFiltering(b: boolean);
+        private _realTimeFilteringQuality;
+        /**
+         * Quality switch for realtime filtering
+         */
+        get realTimeFilteringQuality(): number;
+        set realTimeFilteringQuality(n: number);
         /**
          * Force normal to face away from face.
          */
@@ -61115,7 +61162,7 @@ declare module "babylonjs/Materials/Textures/Filtering/hdrFiltering" {
           * @param onFinished Callback when filtering is done
           * @return Promise called when prefiltering is done
           */
-        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown>;
+        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown> | undefined;
     }
 }
 declare module "babylonjs/Materials/Textures/hdrCubeTexture" {
@@ -87195,13 +87242,25 @@ declare module BABYLON {
          * @param delay defines the start delay (in ms)
          * @param onAnimationEnd defines a callback to call when animation ends
          */
-        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
+        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd?: Nullable<() => void>): void;
         /** Stops current animation (if any) */
         stopAnimation(): void;
         /** @hidden */
         _animate(deltaTime: number): void;
         /** Release associated resources */
         dispose(): void;
+        /**
+         * Serializes the sprite to a JSON object
+         * @returns the JSON object
+         */
+        serialize(): any;
+        /**
+         * Parses a JSON object to create a new sprite
+         * @param parsedSprite The JSON object to parse
+         * @param manager defines the hosting manager
+         * @returns the new sprite
+         */
+        static Parse(parsedSprite: any, manager: SpriteManager): Sprite;
     }
 }
 declare module BABYLON {
@@ -87835,6 +87894,10 @@ declare module BABYLON {
     export class SpriteManager implements ISpriteManager {
         /** defines the manager's name */
         name: string;
+        /** Define the Url to load snippets */
+        static SnippetUrl: string;
+        /** Snippet ID if the manager was created from the snippet server */
+        snippetId: string;
         /** Gets the list of sprites */
         sprites: Sprite[];
         /** Gets or sets the rendering group id (0 by default) */
@@ -87958,6 +88021,28 @@ declare module BABYLON {
          * Release associated resources
          */
         dispose(): void;
+        /**
+         * Serializes the sprite manager to a JSON object
+         * @param serializeTexture defines if the texture must be serialized as well
+         * @returns the JSON object
+         */
+        serialize(serializeTexture?: boolean): any;
+        /**
+         * Parses a JSON object to create a new sprite manager.
+         * @param parsedManager The JSON object to parse
+         * @param scene The scene to create the sprite managerin
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the new sprite manager
+         */
+        static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager;
+        /**
+         * Creates a sprite manager from a snippet saved by the sprite editor
+         * @param snippetId defines the snippet to load
+         * @param scene defines the hosting scene
+         * @param rootUrl defines the root URL to use to load textures and relative dependencies
+         * @returns a promise that will resolve to the new sprite manager
+         */
+        static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl?: string): Promise<SpriteManager>;
     }
 }
 declare module BABYLON {
@@ -93062,6 +93147,13 @@ declare module BABYLON {
          */
         get sourceMesh(): Mesh;
         /**
+         * Creates a new InstancedMesh object from the mesh model.
+         * @see http://doc.babylonjs.com/how_to/how_to_use_instances
+         * @param name defines the name of the new instance
+         * @returns a new InstancedMesh
+         */
+        createInstance(name: string): InstancedMesh;
+        /**
          * Is this node ready to be used/rendered
          * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
          * @return {boolean} is it ready
@@ -109693,18 +109785,6 @@ declare module BABYLON {
          * @returns "BaseTexture"
          */
         getClassName(): string;
-        private _realTimeFiltering;
-        /**
-         * Enables realtime filtering on the texture.
-         */
-        get realTimeFiltering(): boolean;
-        set realTimeFiltering(b: boolean);
-        private _realTimeFilteringQuality;
-        /**
-         * Quality switch for realtime filtering
-         */
-        get realTimeFilteringQuality(): number;
-        set realTimeFilteringQuality(n: number);
         /**
          * Define the list of animation attached to the texture.
          */
@@ -114015,9 +114095,10 @@ declare module BABYLON {
         static MakeArray(obj: any, allowsNullUndefined?: boolean): Nullable<Array<any>>;
         /**
          * Gets the pointer prefix to use
+         * @param engine defines the engine we are finding the prefix for
          * @returns "pointer" if touch is enabled. Else returns "mouse"
          */
-        static GetPointerPrefix(): string;
+        static GetPointerPrefix(engine: Engine): string;
         /**
          * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
          * @param url define the url we are trying
@@ -130968,10 +131049,11 @@ declare module BABYLON {
          * @param uniformBuffer defines the Uniform buffer to fill in.
          * @param scene defines the scene the material belongs to.
          * @param engine defines the engine the material belongs to.
-         * @param isFrozen defines wether the material is frozen or not.
-         * @param lodBasedMicrosurface defines wether the material relies on lod based microsurface or not.
+         * @param isFrozen defines whether the material is frozen or not.
+         * @param lodBasedMicrosurface defines whether the material relies on lod based microsurface or not.
+         * @param realTimeFiltering defines whether the textures should be filtered on the fly.
          */
-        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean): void;
+        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean, realTimeFiltering: boolean): void;
         /**
          * Unbinds the material from the mesh.
          * @param activeEffect defines the effect that should be unbound from.
@@ -131803,6 +131885,18 @@ declare module BABYLON {
          * Force the shader to compute irradiance in the fragment shader in order to take bump in account.
          */
         protected _forceIrradianceInFragment: boolean;
+        private _realTimeFiltering;
+        /**
+         * Enables realtime filtering on the texture.
+         */
+        get realTimeFiltering(): boolean;
+        set realTimeFiltering(b: boolean);
+        private _realTimeFilteringQuality;
+        /**
+         * Quality switch for realtime filtering
+         */
+        get realTimeFilteringQuality(): number;
+        set realTimeFilteringQuality(n: number);
         /**
          * Force normal to face away from face.
          */
@@ -135364,7 +135458,7 @@ declare module BABYLON {
           * @param onFinished Callback when filtering is done
           * @return Promise called when prefiltering is done
           */
-        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown>;
+        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown> | undefined;
     }
 }
 declare module BABYLON {

+ 65 - 18
dist/preview release/documentation.d.ts

@@ -10258,13 +10258,25 @@ declare module BABYLON {
          * @param delay defines the start delay (in ms)
          * @param onAnimationEnd defines a callback to call when animation ends
          */
-        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
+        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd?: Nullable<() => void>): void;
         /** Stops current animation (if any) */
         stopAnimation(): void;
         /** @hidden */
         _animate(deltaTime: number): void;
         /** Release associated resources */
         dispose(): void;
+        /**
+         * Serializes the sprite to a JSON object
+         * @returns the JSON object
+         */
+        serialize(): any;
+        /**
+         * Parses a JSON object to create a new sprite
+         * @param parsedSprite The JSON object to parse
+         * @param manager defines the hosting manager
+         * @returns the new sprite
+         */
+        static Parse(parsedSprite: any, manager: SpriteManager): Sprite;
     }
 }
 declare module BABYLON {
@@ -10898,6 +10910,10 @@ declare module BABYLON {
     export class SpriteManager implements ISpriteManager {
         /** defines the manager's name */
         name: string;
+        /** Define the Url to load snippets */
+        static SnippetUrl: string;
+        /** Snippet ID if the manager was created from the snippet server */
+        snippetId: string;
         /** Gets the list of sprites */
         sprites: Sprite[];
         /** Gets or sets the rendering group id (0 by default) */
@@ -11021,6 +11037,28 @@ declare module BABYLON {
          * Release associated resources
          */
         dispose(): void;
+        /**
+         * Serializes the sprite manager to a JSON object
+         * @param serializeTexture defines if the texture must be serialized as well
+         * @returns the JSON object
+         */
+        serialize(serializeTexture?: boolean): any;
+        /**
+         * Parses a JSON object to create a new sprite manager.
+         * @param parsedManager The JSON object to parse
+         * @param scene The scene to create the sprite managerin
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the new sprite manager
+         */
+        static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager;
+        /**
+         * Creates a sprite manager from a snippet saved by the sprite editor
+         * @param snippetId defines the snippet to load
+         * @param scene defines the hosting scene
+         * @param rootUrl defines the root URL to use to load textures and relative dependencies
+         * @returns a promise that will resolve to the new sprite manager
+         */
+        static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl?: string): Promise<SpriteManager>;
     }
 }
 declare module BABYLON {
@@ -16125,6 +16163,13 @@ declare module BABYLON {
          */
         get sourceMesh(): Mesh;
         /**
+         * Creates a new InstancedMesh object from the mesh model.
+         * @see http://doc.babylonjs.com/how_to/how_to_use_instances
+         * @param name defines the name of the new instance
+         * @returns a new InstancedMesh
+         */
+        createInstance(name: string): InstancedMesh;
+        /**
          * Is this node ready to be used/rendered
          * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
          * @return {boolean} is it ready
@@ -32756,18 +32801,6 @@ declare module BABYLON {
          * @returns "BaseTexture"
          */
         getClassName(): string;
-        private _realTimeFiltering;
-        /**
-         * Enables realtime filtering on the texture.
-         */
-        get realTimeFiltering(): boolean;
-        set realTimeFiltering(b: boolean);
-        private _realTimeFilteringQuality;
-        /**
-         * Quality switch for realtime filtering
-         */
-        get realTimeFilteringQuality(): number;
-        set realTimeFilteringQuality(n: number);
         /**
          * Define the list of animation attached to the texture.
          */
@@ -37078,9 +37111,10 @@ declare module BABYLON {
         static MakeArray(obj: any, allowsNullUndefined?: boolean): Nullable<Array<any>>;
         /**
          * Gets the pointer prefix to use
+         * @param engine defines the engine we are finding the prefix for
          * @returns "pointer" if touch is enabled. Else returns "mouse"
          */
-        static GetPointerPrefix(): string;
+        static GetPointerPrefix(engine: Engine): string;
         /**
          * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
          * @param url define the url we are trying
@@ -54031,10 +54065,11 @@ declare module BABYLON {
          * @param uniformBuffer defines the Uniform buffer to fill in.
          * @param scene defines the scene the material belongs to.
          * @param engine defines the engine the material belongs to.
-         * @param isFrozen defines wether the material is frozen or not.
-         * @param lodBasedMicrosurface defines wether the material relies on lod based microsurface or not.
+         * @param isFrozen defines whether the material is frozen or not.
+         * @param lodBasedMicrosurface defines whether the material relies on lod based microsurface or not.
+         * @param realTimeFiltering defines whether the textures should be filtered on the fly.
          */
-        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean): void;
+        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean, realTimeFiltering: boolean): void;
         /**
          * Unbinds the material from the mesh.
          * @param activeEffect defines the effect that should be unbound from.
@@ -54866,6 +54901,18 @@ declare module BABYLON {
          * Force the shader to compute irradiance in the fragment shader in order to take bump in account.
          */
         protected _forceIrradianceInFragment: boolean;
+        private _realTimeFiltering;
+        /**
+         * Enables realtime filtering on the texture.
+         */
+        get realTimeFiltering(): boolean;
+        set realTimeFiltering(b: boolean);
+        private _realTimeFilteringQuality;
+        /**
+         * Quality switch for realtime filtering
+         */
+        get realTimeFilteringQuality(): number;
+        set realTimeFilteringQuality(n: number);
         /**
          * Force normal to face away from face.
          */
@@ -58427,7 +58474,7 @@ declare module BABYLON {
           * @param onFinished Callback when filtering is done
           * @return Promise called when prefiltering is done
           */
-        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown>;
+        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown> | undefined;
     }
 }
 declare module BABYLON {

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


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


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


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

@@ -1852,9 +1852,14 @@ declare module INSPECTOR {
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
     }
     export class SpriteManagerPropertyGridComponent extends React.Component<ISpriteManagerPropertyGridComponentProps> {
+        private _snippetUrl;
         constructor(props: ISpriteManagerPropertyGridComponentProps);
         addNewSprite(): void;
         disposeManager(): void;
+        saveToFile(): void;
+        loadFromFile(file: File): void;
+        loadFromSnippet(): void;
+        saveToSnippet(): void;
         render(): JSX.Element;
     }
 }

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

@@ -2351,9 +2351,14 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/spr
         onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
     }
     export class SpriteManagerPropertyGridComponent extends React.Component<ISpriteManagerPropertyGridComponentProps> {
+        private _snippetUrl;
         constructor(props: ISpriteManagerPropertyGridComponentProps);
         addNewSprite(): void;
         disposeManager(): void;
+        saveToFile(): void;
+        loadFromFile(file: File): void;
+        loadFromSnippet(): void;
+        saveToSnippet(): void;
         render(): JSX.Element;
     }
 }
@@ -4934,9 +4939,14 @@ declare module INSPECTOR {
         onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
     }
     export class SpriteManagerPropertyGridComponent extends React.Component<ISpriteManagerPropertyGridComponentProps> {
+        private _snippetUrl;
         constructor(props: ISpriteManagerPropertyGridComponentProps);
         addNewSprite(): void;
         disposeManager(): void;
+        saveToFile(): void;
+        loadFromFile(file: File): void;
+        loadFromSnippet(): void;
+        saveToSnippet(): void;
         render(): JSX.Element;
     }
 }

+ 51 - 51
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -290,60 +290,60 @@ var EXT_mesh_gpu_instancing = /** @class */ (function () {
     EXT_mesh_gpu_instancing.prototype.loadNodeAsync = function (context, node, assign) {
         var _this = this;
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].LoadExtensionAsync(context, node, this.name, function (extensionContext, extension) {
-            return _this._loader.loadNodeAsync("#/nodes/" + node.index, node, function (babylonTransformNode) {
-                var promises = new Array();
-                var instanceCount = null;
-                var loadAttribute = function (attribute, assignBufferFunc) {
-                    if (extension.attributes[attribute] == undefined) {
-                        return;
-                    }
-                    var accessor = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext + "/attributes/" + attribute, _this._loader.gltf.accessors, extension.attributes[attribute]);
-                    if (instanceCount === null) {
-                        instanceCount = accessor.count;
-                    }
-                    else if (instanceCount !== accessor.count) {
-                        throw new Error(extensionContext + "/attributes: Instance buffer accessors do not have the same count.");
-                    }
-                    promises.push(_this._loader._loadFloatAccessorAsync("/accessors/" + accessor.bufferView, accessor).then(function (data) {
-                        assignBufferFunc(data);
-                    }));
-                };
-                var translationBuffer = null;
-                var rotationBuffer = null;
-                var scaleBuffer = null;
-                loadAttribute("TRANSLATION", function (data) { translationBuffer = data; });
-                loadAttribute("ROTATION", function (data) { rotationBuffer = data; });
-                loadAttribute("SCALE", function (data) { scaleBuffer = data; });
-                return Promise.all(promises).then(function () {
-                    if (instanceCount) {
-                        var instanceName = "";
-                        var instance = null;
-                        var digitLength = instanceCount.toString().length;
+            var promise = _this._loader.loadNodeAsync("#/nodes/" + node.index, node, assign);
+            if (!node._primitiveBabylonMeshes) {
+                return promise;
+            }
+            // Hide the source meshes.
+            for (var _i = 0, _a = node._primitiveBabylonMeshes; _i < _a.length; _i++) {
+                var babylonMesh = _a[_i];
+                babylonMesh.isVisible = false;
+            }
+            var promises = new Array();
+            var instanceCount = 0;
+            var loadAttribute = function (attribute) {
+                if (extension.attributes[attribute] == undefined) {
+                    promises.push(Promise.resolve(null));
+                    return;
+                }
+                var accessor = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext + "/attributes/" + attribute, _this._loader.gltf.accessors, extension.attributes[attribute]);
+                promises.push(_this._loader._loadFloatAccessorAsync("/accessors/" + accessor.bufferView, accessor));
+                if (instanceCount === 0) {
+                    instanceCount = accessor.count;
+                }
+                else if (instanceCount !== accessor.count) {
+                    throw new Error(extensionContext + "/attributes: Instance buffer accessors do not have the same count.");
+                }
+            };
+            loadAttribute("TRANSLATION");
+            loadAttribute("ROTATION");
+            loadAttribute("SCALE");
+            if (instanceCount == 0) {
+                return promise;
+            }
+            var digitLength = instanceCount.toString().length;
+            for (var i = 0; i < instanceCount; ++i) {
+                for (var _b = 0, _c = node._primitiveBabylonMeshes; _b < _c.length; _b++) {
+                    var babylonMesh = _c[_b];
+                    var instanceName = (babylonMesh.name || babylonMesh.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
+                    var babylonInstancedMesh = babylonMesh.createInstance(instanceName);
+                    babylonInstancedMesh.setParent(babylonMesh);
+                }
+            }
+            return promise.then(function (babylonTransformNode) {
+                return Promise.all(promises).then(function (_a) {
+                    var translationBuffer = _a[0], rotationBuffer = _a[1], scaleBuffer = _a[2];
+                    for (var _i = 0, _b = node._primitiveBabylonMeshes; _i < _b.length; _i++) {
+                        var babylonMesh = _b[_i];
+                        var babylonInstancedMeshes = babylonMesh.getChildMeshes(true, function (node) { return node.isAnInstance; });
                         for (var i = 0; i < instanceCount; ++i) {
-                            if (node._primitiveBabylonMeshes) {
-                                for (var j = 0; j < node._primitiveBabylonMeshes.length; ++j) {
-                                    var babylonMeshPrimitive = node._primitiveBabylonMeshes[j];
-                                    instanceName = (babylonMeshPrimitive.name || babylonMeshPrimitive.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
-                                    if (babylonMeshPrimitive.isAnInstance) {
-                                        instance = babylonMeshPrimitive.sourceMesh.createInstance(instanceName);
-                                    }
-                                    else if (babylonMeshPrimitive.createInstance) {
-                                        instance = babylonMeshPrimitive.createInstance(instanceName);
-                                    }
-                                    if (instance) {
-                                        instance.setParent(babylonMeshPrimitive);
-                                        translationBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, instance.position)
-                                            : instance.position.set(0, 0, 0);
-                                        rotationBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, instance.rotationQuaternion)
-                                            : instance.rotationQuaternion.set(0, 0, 0, 1);
-                                        scaleBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, instance.scaling)
-                                            : instance.scaling.set(1, 1, 1);
-                                    }
-                                }
-                            }
+                            var babylonInstancedMesh = babylonInstancedMeshes[i];
+                            translationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
+                            rotationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion);
+                            scaleBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
+                            babylonInstancedMesh.refreshBoundingInfo();
                         }
                     }
-                    assign(babylonTransformNode);
                     return babylonTransformNode;
                 });
             });

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


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


+ 51 - 51
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2870,60 +2870,60 @@ var EXT_mesh_gpu_instancing = /** @class */ (function () {
     EXT_mesh_gpu_instancing.prototype.loadNodeAsync = function (context, node, assign) {
         var _this = this;
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].LoadExtensionAsync(context, node, this.name, function (extensionContext, extension) {
-            return _this._loader.loadNodeAsync("#/nodes/" + node.index, node, function (babylonTransformNode) {
-                var promises = new Array();
-                var instanceCount = null;
-                var loadAttribute = function (attribute, assignBufferFunc) {
-                    if (extension.attributes[attribute] == undefined) {
-                        return;
-                    }
-                    var accessor = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext + "/attributes/" + attribute, _this._loader.gltf.accessors, extension.attributes[attribute]);
-                    if (instanceCount === null) {
-                        instanceCount = accessor.count;
-                    }
-                    else if (instanceCount !== accessor.count) {
-                        throw new Error(extensionContext + "/attributes: Instance buffer accessors do not have the same count.");
-                    }
-                    promises.push(_this._loader._loadFloatAccessorAsync("/accessors/" + accessor.bufferView, accessor).then(function (data) {
-                        assignBufferFunc(data);
-                    }));
-                };
-                var translationBuffer = null;
-                var rotationBuffer = null;
-                var scaleBuffer = null;
-                loadAttribute("TRANSLATION", function (data) { translationBuffer = data; });
-                loadAttribute("ROTATION", function (data) { rotationBuffer = data; });
-                loadAttribute("SCALE", function (data) { scaleBuffer = data; });
-                return Promise.all(promises).then(function () {
-                    if (instanceCount) {
-                        var instanceName = "";
-                        var instance = null;
-                        var digitLength = instanceCount.toString().length;
+            var promise = _this._loader.loadNodeAsync("#/nodes/" + node.index, node, assign);
+            if (!node._primitiveBabylonMeshes) {
+                return promise;
+            }
+            // Hide the source meshes.
+            for (var _i = 0, _a = node._primitiveBabylonMeshes; _i < _a.length; _i++) {
+                var babylonMesh = _a[_i];
+                babylonMesh.isVisible = false;
+            }
+            var promises = new Array();
+            var instanceCount = 0;
+            var loadAttribute = function (attribute) {
+                if (extension.attributes[attribute] == undefined) {
+                    promises.push(Promise.resolve(null));
+                    return;
+                }
+                var accessor = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext + "/attributes/" + attribute, _this._loader.gltf.accessors, extension.attributes[attribute]);
+                promises.push(_this._loader._loadFloatAccessorAsync("/accessors/" + accessor.bufferView, accessor));
+                if (instanceCount === 0) {
+                    instanceCount = accessor.count;
+                }
+                else if (instanceCount !== accessor.count) {
+                    throw new Error(extensionContext + "/attributes: Instance buffer accessors do not have the same count.");
+                }
+            };
+            loadAttribute("TRANSLATION");
+            loadAttribute("ROTATION");
+            loadAttribute("SCALE");
+            if (instanceCount == 0) {
+                return promise;
+            }
+            var digitLength = instanceCount.toString().length;
+            for (var i = 0; i < instanceCount; ++i) {
+                for (var _b = 0, _c = node._primitiveBabylonMeshes; _b < _c.length; _b++) {
+                    var babylonMesh = _c[_b];
+                    var instanceName = (babylonMesh.name || babylonMesh.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
+                    var babylonInstancedMesh = babylonMesh.createInstance(instanceName);
+                    babylonInstancedMesh.setParent(babylonMesh);
+                }
+            }
+            return promise.then(function (babylonTransformNode) {
+                return Promise.all(promises).then(function (_a) {
+                    var translationBuffer = _a[0], rotationBuffer = _a[1], scaleBuffer = _a[2];
+                    for (var _i = 0, _b = node._primitiveBabylonMeshes; _i < _b.length; _i++) {
+                        var babylonMesh = _b[_i];
+                        var babylonInstancedMeshes = babylonMesh.getChildMeshes(true, function (node) { return node.isAnInstance; });
                         for (var i = 0; i < instanceCount; ++i) {
-                            if (node._primitiveBabylonMeshes) {
-                                for (var j = 0; j < node._primitiveBabylonMeshes.length; ++j) {
-                                    var babylonMeshPrimitive = node._primitiveBabylonMeshes[j];
-                                    instanceName = (babylonMeshPrimitive.name || babylonMeshPrimitive.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
-                                    if (babylonMeshPrimitive.isAnInstance) {
-                                        instance = babylonMeshPrimitive.sourceMesh.createInstance(instanceName);
-                                    }
-                                    else if (babylonMeshPrimitive.createInstance) {
-                                        instance = babylonMeshPrimitive.createInstance(instanceName);
-                                    }
-                                    if (instance) {
-                                        instance.setParent(babylonMeshPrimitive);
-                                        translationBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, instance.position)
-                                            : instance.position.set(0, 0, 0);
-                                        rotationBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, instance.rotationQuaternion)
-                                            : instance.rotationQuaternion.set(0, 0, 0, 1);
-                                        scaleBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, instance.scaling)
-                                            : instance.scaling.set(1, 1, 1);
-                                    }
-                                }
-                            }
+                            var babylonInstancedMesh = babylonInstancedMeshes[i];
+                            translationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
+                            rotationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion);
+                            scaleBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
+                            babylonInstancedMesh.refreshBoundingInfo();
                         }
                     }
-                    assign(babylonTransformNode);
                     return babylonTransformNode;
                 });
             });

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


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


+ 51 - 51
dist/preview release/loaders/babylonjs.loaders.js

@@ -4250,60 +4250,60 @@ var EXT_mesh_gpu_instancing = /** @class */ (function () {
     EXT_mesh_gpu_instancing.prototype.loadNodeAsync = function (context, node, assign) {
         var _this = this;
         return _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["GLTFLoader"].LoadExtensionAsync(context, node, this.name, function (extensionContext, extension) {
-            return _this._loader.loadNodeAsync("#/nodes/" + node.index, node, function (babylonTransformNode) {
-                var promises = new Array();
-                var instanceCount = null;
-                var loadAttribute = function (attribute, assignBufferFunc) {
-                    if (extension.attributes[attribute] == undefined) {
-                        return;
-                    }
-                    var accessor = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext + "/attributes/" + attribute, _this._loader.gltf.accessors, extension.attributes[attribute]);
-                    if (instanceCount === null) {
-                        instanceCount = accessor.count;
-                    }
-                    else if (instanceCount !== accessor.count) {
-                        throw new Error(extensionContext + "/attributes: Instance buffer accessors do not have the same count.");
-                    }
-                    promises.push(_this._loader._loadFloatAccessorAsync("/accessors/" + accessor.bufferView, accessor).then(function (data) {
-                        assignBufferFunc(data);
-                    }));
-                };
-                var translationBuffer = null;
-                var rotationBuffer = null;
-                var scaleBuffer = null;
-                loadAttribute("TRANSLATION", function (data) { translationBuffer = data; });
-                loadAttribute("ROTATION", function (data) { rotationBuffer = data; });
-                loadAttribute("SCALE", function (data) { scaleBuffer = data; });
-                return Promise.all(promises).then(function () {
-                    if (instanceCount) {
-                        var instanceName = "";
-                        var instance = null;
-                        var digitLength = instanceCount.toString().length;
+            var promise = _this._loader.loadNodeAsync("#/nodes/" + node.index, node, assign);
+            if (!node._primitiveBabylonMeshes) {
+                return promise;
+            }
+            // Hide the source meshes.
+            for (var _i = 0, _a = node._primitiveBabylonMeshes; _i < _a.length; _i++) {
+                var babylonMesh = _a[_i];
+                babylonMesh.isVisible = false;
+            }
+            var promises = new Array();
+            var instanceCount = 0;
+            var loadAttribute = function (attribute) {
+                if (extension.attributes[attribute] == undefined) {
+                    promises.push(Promise.resolve(null));
+                    return;
+                }
+                var accessor = _glTFLoader__WEBPACK_IMPORTED_MODULE_1__["ArrayItem"].Get(extensionContext + "/attributes/" + attribute, _this._loader.gltf.accessors, extension.attributes[attribute]);
+                promises.push(_this._loader._loadFloatAccessorAsync("/accessors/" + accessor.bufferView, accessor));
+                if (instanceCount === 0) {
+                    instanceCount = accessor.count;
+                }
+                else if (instanceCount !== accessor.count) {
+                    throw new Error(extensionContext + "/attributes: Instance buffer accessors do not have the same count.");
+                }
+            };
+            loadAttribute("TRANSLATION");
+            loadAttribute("ROTATION");
+            loadAttribute("SCALE");
+            if (instanceCount == 0) {
+                return promise;
+            }
+            var digitLength = instanceCount.toString().length;
+            for (var i = 0; i < instanceCount; ++i) {
+                for (var _b = 0, _c = node._primitiveBabylonMeshes; _b < _c.length; _b++) {
+                    var babylonMesh = _c[_b];
+                    var instanceName = (babylonMesh.name || babylonMesh.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
+                    var babylonInstancedMesh = babylonMesh.createInstance(instanceName);
+                    babylonInstancedMesh.setParent(babylonMesh);
+                }
+            }
+            return promise.then(function (babylonTransformNode) {
+                return Promise.all(promises).then(function (_a) {
+                    var translationBuffer = _a[0], rotationBuffer = _a[1], scaleBuffer = _a[2];
+                    for (var _i = 0, _b = node._primitiveBabylonMeshes; _i < _b.length; _i++) {
+                        var babylonMesh = _b[_i];
+                        var babylonInstancedMeshes = babylonMesh.getChildMeshes(true, function (node) { return node.isAnInstance; });
                         for (var i = 0; i < instanceCount; ++i) {
-                            if (node._primitiveBabylonMeshes) {
-                                for (var j = 0; j < node._primitiveBabylonMeshes.length; ++j) {
-                                    var babylonMeshPrimitive = node._primitiveBabylonMeshes[j];
-                                    instanceName = (babylonMeshPrimitive.name || babylonMeshPrimitive.id) + "_" + babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["StringTools"].PadNumber(i, digitLength);
-                                    if (babylonMeshPrimitive.isAnInstance) {
-                                        instance = babylonMeshPrimitive.sourceMesh.createInstance(instanceName);
-                                    }
-                                    else if (babylonMeshPrimitive.createInstance) {
-                                        instance = babylonMeshPrimitive.createInstance(instanceName);
-                                    }
-                                    if (instance) {
-                                        instance.setParent(babylonMeshPrimitive);
-                                        translationBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, instance.position)
-                                            : instance.position.set(0, 0, 0);
-                                        rotationBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, instance.rotationQuaternion)
-                                            : instance.rotationQuaternion.set(0, 0, 0, 1);
-                                        scaleBuffer ? babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, instance.scaling)
-                                            : instance.scaling.set(1, 1, 1);
-                                    }
-                                }
-                            }
+                            var babylonInstancedMesh = babylonInstancedMeshes[i];
+                            translationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(translationBuffer, i * 3, babylonInstancedMesh.position);
+                            rotationBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Quaternion"].FromArrayToRef(rotationBuffer, i * 4, babylonInstancedMesh.rotationQuaternion);
+                            scaleBuffer && babylonjs_Maths_math_vector__WEBPACK_IMPORTED_MODULE_0__["Vector3"].FromArrayToRef(scaleBuffer, i * 3, babylonInstancedMesh.scaling);
+                            babylonInstancedMesh.refreshBoundingInfo();
                         }
                     }
-                    assign(babylonTransformNode);
                     return babylonTransformNode;
                 });
             });

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


File diff suppressed because it is too large
+ 2 - 2
dist/preview release/loaders/babylonjs.loaders.min.js


+ 131 - 37
dist/preview release/viewer/babylon.module.d.ts

@@ -10316,7 +10316,7 @@ declare module "babylonjs/Sprites/sprite" {
     import { Vector3 } from "babylonjs/Maths/math.vector";
     import { Nullable } from "babylonjs/types";
     import { ActionManager } from "babylonjs/Actions/actionManager";
-    import { ISpriteManager } from "babylonjs/Sprites/spriteManager";
+    import { ISpriteManager, SpriteManager } from "babylonjs/Sprites/spriteManager";
     import { Color4 } from "babylonjs/Maths/math.color";
     import { Observable } from "babylonjs/Misc/observable";
     import { IAnimatable } from "babylonjs/Animations/animatable.interface";
@@ -10433,13 +10433,25 @@ declare module "babylonjs/Sprites/sprite" {
          * @param delay defines the start delay (in ms)
          * @param onAnimationEnd defines a callback to call when animation ends
          */
-        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
+        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd?: Nullable<() => void>): void;
         /** Stops current animation (if any) */
         stopAnimation(): void;
         /** @hidden */
         _animate(deltaTime: number): void;
         /** Release associated resources */
         dispose(): void;
+        /**
+         * Serializes the sprite to a JSON object
+         * @returns the JSON object
+         */
+        serialize(): any;
+        /**
+         * Parses a JSON object to create a new sprite
+         * @param parsedSprite The JSON object to parse
+         * @param manager defines the hosting manager
+         * @returns the new sprite
+         */
+        static Parse(parsedSprite: any, manager: SpriteManager): Sprite;
     }
 }
 declare module "babylonjs/Collisions/pickingInfo" {
@@ -11123,6 +11135,10 @@ declare module "babylonjs/Sprites/spriteManager" {
     export class SpriteManager implements ISpriteManager {
         /** defines the manager's name */
         name: string;
+        /** Define the Url to load snippets */
+        static SnippetUrl: string;
+        /** Snippet ID if the manager was created from the snippet server */
+        snippetId: string;
         /** Gets the list of sprites */
         sprites: Sprite[];
         /** Gets or sets the rendering group id (0 by default) */
@@ -11246,6 +11262,28 @@ declare module "babylonjs/Sprites/spriteManager" {
          * Release associated resources
          */
         dispose(): void;
+        /**
+         * Serializes the sprite manager to a JSON object
+         * @param serializeTexture defines if the texture must be serialized as well
+         * @returns the JSON object
+         */
+        serialize(serializeTexture?: boolean): any;
+        /**
+         * Parses a JSON object to create a new sprite manager.
+         * @param parsedManager The JSON object to parse
+         * @param scene The scene to create the sprite managerin
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the new sprite manager
+         */
+        static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager;
+        /**
+         * Creates a sprite manager from a snippet saved by the sprite editor
+         * @param snippetId defines the snippet to load
+         * @param scene defines the hosting scene
+         * @param rootUrl defines the root URL to use to load textures and relative dependencies
+         * @returns a promise that will resolve to the new sprite manager
+         */
+        static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl?: string): Promise<SpriteManager>;
     }
 }
 declare module "babylonjs/Misc/gradients" {
@@ -16544,6 +16582,13 @@ declare module "babylonjs/Meshes/instancedMesh" {
          */
         get sourceMesh(): Mesh;
         /**
+         * Creates a new InstancedMesh object from the mesh model.
+         * @see http://doc.babylonjs.com/how_to/how_to_use_instances
+         * @param name defines the name of the new instance
+         * @returns a new InstancedMesh
+         */
+        createInstance(name: string): InstancedMesh;
+        /**
          * Is this node ready to be used/rendered
          * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
          * @return {boolean} is it ready
@@ -33879,18 +33924,6 @@ declare module "babylonjs/Materials/Textures/baseTexture" {
          * @returns "BaseTexture"
          */
         getClassName(): string;
-        private _realTimeFiltering;
-        /**
-         * Enables realtime filtering on the texture.
-         */
-        get realTimeFiltering(): boolean;
-        set realTimeFiltering(b: boolean);
-        private _realTimeFilteringQuality;
-        /**
-         * Quality switch for realtime filtering
-         */
-        get realTimeFilteringQuality(): number;
-        set realTimeFilteringQuality(n: number);
         /**
          * Define the list of animation attached to the texture.
          */
@@ -38300,9 +38333,10 @@ declare module "babylonjs/Misc/tools" {
         static MakeArray(obj: any, allowsNullUndefined?: boolean): Nullable<Array<any>>;
         /**
          * Gets the pointer prefix to use
+         * @param engine defines the engine we are finding the prefix for
          * @returns "pointer" if touch is enabled. Else returns "mouse"
          */
-        static GetPointerPrefix(): string;
+        static GetPointerPrefix(engine: Engine): string;
         /**
          * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
          * @param url define the url we are trying
@@ -56374,10 +56408,11 @@ declare module "babylonjs/Materials/PBR/pbrSubSurfaceConfiguration" {
          * @param uniformBuffer defines the Uniform buffer to fill in.
          * @param scene defines the scene the material belongs to.
          * @param engine defines the engine the material belongs to.
-         * @param isFrozen defines wether the material is frozen or not.
-         * @param lodBasedMicrosurface defines wether the material relies on lod based microsurface or not.
+         * @param isFrozen defines whether the material is frozen or not.
+         * @param lodBasedMicrosurface defines whether the material relies on lod based microsurface or not.
+         * @param realTimeFiltering defines whether the textures should be filtered on the fly.
          */
-        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean): void;
+        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean, realTimeFiltering: boolean): void;
         /**
          * Unbinds the material from the mesh.
          * @param activeEffect defines the effect that should be unbound from.
@@ -57303,6 +57338,18 @@ declare module "babylonjs/Materials/PBR/pbrBaseMaterial" {
          * Force the shader to compute irradiance in the fragment shader in order to take bump in account.
          */
         protected _forceIrradianceInFragment: boolean;
+        private _realTimeFiltering;
+        /**
+         * Enables realtime filtering on the texture.
+         */
+        get realTimeFiltering(): boolean;
+        set realTimeFiltering(b: boolean);
+        private _realTimeFilteringQuality;
+        /**
+         * Quality switch for realtime filtering
+         */
+        get realTimeFilteringQuality(): number;
+        set realTimeFilteringQuality(n: number);
         /**
          * Force normal to face away from face.
          */
@@ -61115,7 +61162,7 @@ declare module "babylonjs/Materials/Textures/Filtering/hdrFiltering" {
           * @param onFinished Callback when filtering is done
           * @return Promise called when prefiltering is done
           */
-        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown>;
+        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown> | undefined;
     }
 }
 declare module "babylonjs/Materials/Textures/hdrCubeTexture" {
@@ -87195,13 +87242,25 @@ declare module BABYLON {
          * @param delay defines the start delay (in ms)
          * @param onAnimationEnd defines a callback to call when animation ends
          */
-        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void;
+        playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd?: Nullable<() => void>): void;
         /** Stops current animation (if any) */
         stopAnimation(): void;
         /** @hidden */
         _animate(deltaTime: number): void;
         /** Release associated resources */
         dispose(): void;
+        /**
+         * Serializes the sprite to a JSON object
+         * @returns the JSON object
+         */
+        serialize(): any;
+        /**
+         * Parses a JSON object to create a new sprite
+         * @param parsedSprite The JSON object to parse
+         * @param manager defines the hosting manager
+         * @returns the new sprite
+         */
+        static Parse(parsedSprite: any, manager: SpriteManager): Sprite;
     }
 }
 declare module BABYLON {
@@ -87835,6 +87894,10 @@ declare module BABYLON {
     export class SpriteManager implements ISpriteManager {
         /** defines the manager's name */
         name: string;
+        /** Define the Url to load snippets */
+        static SnippetUrl: string;
+        /** Snippet ID if the manager was created from the snippet server */
+        snippetId: string;
         /** Gets the list of sprites */
         sprites: Sprite[];
         /** Gets or sets the rendering group id (0 by default) */
@@ -87958,6 +88021,28 @@ declare module BABYLON {
          * Release associated resources
          */
         dispose(): void;
+        /**
+         * Serializes the sprite manager to a JSON object
+         * @param serializeTexture defines if the texture must be serialized as well
+         * @returns the JSON object
+         */
+        serialize(serializeTexture?: boolean): any;
+        /**
+         * Parses a JSON object to create a new sprite manager.
+         * @param parsedManager The JSON object to parse
+         * @param scene The scene to create the sprite managerin
+         * @param rootUrl The root url to use to load external dependencies like texture
+         * @returns the new sprite manager
+         */
+        static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager;
+        /**
+         * Creates a sprite manager from a snippet saved by the sprite editor
+         * @param snippetId defines the snippet to load
+         * @param scene defines the hosting scene
+         * @param rootUrl defines the root URL to use to load textures and relative dependencies
+         * @returns a promise that will resolve to the new sprite manager
+         */
+        static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl?: string): Promise<SpriteManager>;
     }
 }
 declare module BABYLON {
@@ -93062,6 +93147,13 @@ declare module BABYLON {
          */
         get sourceMesh(): Mesh;
         /**
+         * Creates a new InstancedMesh object from the mesh model.
+         * @see http://doc.babylonjs.com/how_to/how_to_use_instances
+         * @param name defines the name of the new instance
+         * @returns a new InstancedMesh
+         */
+        createInstance(name: string): InstancedMesh;
+        /**
          * Is this node ready to be used/rendered
          * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
          * @return {boolean} is it ready
@@ -109693,18 +109785,6 @@ declare module BABYLON {
          * @returns "BaseTexture"
          */
         getClassName(): string;
-        private _realTimeFiltering;
-        /**
-         * Enables realtime filtering on the texture.
-         */
-        get realTimeFiltering(): boolean;
-        set realTimeFiltering(b: boolean);
-        private _realTimeFilteringQuality;
-        /**
-         * Quality switch for realtime filtering
-         */
-        get realTimeFilteringQuality(): number;
-        set realTimeFilteringQuality(n: number);
         /**
          * Define the list of animation attached to the texture.
          */
@@ -114015,9 +114095,10 @@ declare module BABYLON {
         static MakeArray(obj: any, allowsNullUndefined?: boolean): Nullable<Array<any>>;
         /**
          * Gets the pointer prefix to use
+         * @param engine defines the engine we are finding the prefix for
          * @returns "pointer" if touch is enabled. Else returns "mouse"
          */
-        static GetPointerPrefix(): string;
+        static GetPointerPrefix(engine: Engine): string;
         /**
          * Sets the cors behavior on a dom element. This will add the required Tools.CorsBehavior to the element.
          * @param url define the url we are trying
@@ -130968,10 +131049,11 @@ declare module BABYLON {
          * @param uniformBuffer defines the Uniform buffer to fill in.
          * @param scene defines the scene the material belongs to.
          * @param engine defines the engine the material belongs to.
-         * @param isFrozen defines wether the material is frozen or not.
-         * @param lodBasedMicrosurface defines wether the material relies on lod based microsurface or not.
+         * @param isFrozen defines whether the material is frozen or not.
+         * @param lodBasedMicrosurface defines whether the material relies on lod based microsurface or not.
+         * @param realTimeFiltering defines whether the textures should be filtered on the fly.
          */
-        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean): void;
+        bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, engine: Engine, isFrozen: boolean, lodBasedMicrosurface: boolean, realTimeFiltering: boolean): void;
         /**
          * Unbinds the material from the mesh.
          * @param activeEffect defines the effect that should be unbound from.
@@ -131803,6 +131885,18 @@ declare module BABYLON {
          * Force the shader to compute irradiance in the fragment shader in order to take bump in account.
          */
         protected _forceIrradianceInFragment: boolean;
+        private _realTimeFiltering;
+        /**
+         * Enables realtime filtering on the texture.
+         */
+        get realTimeFiltering(): boolean;
+        set realTimeFiltering(b: boolean);
+        private _realTimeFilteringQuality;
+        /**
+         * Quality switch for realtime filtering
+         */
+        get realTimeFilteringQuality(): number;
+        set realTimeFilteringQuality(n: number);
         /**
          * Force normal to face away from face.
          */
@@ -135364,7 +135458,7 @@ declare module BABYLON {
           * @param onFinished Callback when filtering is done
           * @return Promise called when prefiltering is done
           */
-        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown>;
+        prefilter(texture: BaseTexture, onFinished?: Nullable<() => void>): Promise<unknown> | undefined;
     }
 }
 declare module BABYLON {

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


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


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

@@ -316,7 +316,7 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
                     }} />
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="FILE">
-                <FileButtonLineComponent label="Load" onClick={(file) => this.loadFromFile(file)} accept=".json" />
+                    <FileButtonLineComponent label="Load" onClick={(file) => this.loadFromFile(file)} accept=".json" />
                     <ButtonLineComponent label="Save" onClick={() => this.saveToFile()} />
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="SNIPPET">

+ 111 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/sprites/spriteManagerPropertyGridComponent.tsx

@@ -16,6 +16,8 @@ import { RenderingManager } from 'babylonjs/Rendering/renderingManager';
 import { TextureLinkLineComponent } from '../../../lines/textureLinkLineComponent';
 import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
 import { Sprite } from 'babylonjs/Sprites/sprite';
+import { Tools } from 'babylonjs/Misc/tools';
+import { FileButtonLineComponent } from '../../../lines/fileButtonLineComponent';
 
 interface ISpriteManagerPropertyGridComponentProps {
     globalState: GlobalState;
@@ -26,6 +28,9 @@ interface ISpriteManagerPropertyGridComponentProps {
 }
 
 export class SpriteManagerPropertyGridComponent extends React.Component<ISpriteManagerPropertyGridComponentProps> {
+    private _snippetUrl = "https://snippet.babylonjs.com";
+
+
     constructor(props: ISpriteManagerPropertyGridComponentProps) {
         super(props);
     }
@@ -54,6 +59,100 @@ export class SpriteManagerPropertyGridComponent extends React.Component<ISpriteM
         this.props.onSelectionChangedObservable?.notifyObservers(null);
     }
 
+    saveToFile() {        
+        const spriteManager = this.props.spriteManager;
+        let content = JSON.stringify(spriteManager.serialize(true));
+
+        Tools.Download(new Blob([content]), "spriteManager.json");
+    }
+
+    loadFromFile(file: File) {
+        const spriteManager = this.props.spriteManager;
+        const scene = spriteManager.scene;
+
+        Tools.ReadFile(file, (data) => {
+            let decoder = new TextDecoder("utf-8");
+            let jsonObject = JSON.parse(decoder.decode(data));
+            
+            spriteManager.dispose();            
+            this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+
+            let newManager = SpriteManager.Parse(jsonObject, scene, "");
+            this.props.globalState.onSelectionChangedObservable.notifyObservers(newManager);
+        }, undefined, true);
+    }
+
+    loadFromSnippet() {
+        const spriteManager = this.props.spriteManager;
+        const scene = spriteManager.scene;
+
+        let snippedID = window.prompt("Please enter the snippet ID to use");
+
+        if (!snippedID) {
+            return;
+        }
+        
+        spriteManager.dispose();            
+        this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+
+        SpriteManager.CreateFromSnippetAsync(snippedID, scene).then((newManager) => {
+            this.props.globalState.onSelectionChangedObservable.notifyObservers(newManager);
+        }).catch(err => {
+            alert("Unable to load your sprite manager: " + err);
+        });
+    }
+
+    saveToSnippet() {
+        const spriteManager = this.props.spriteManager;
+        let content = JSON.stringify(spriteManager.serialize(true));
+
+        var xmlHttp = new XMLHttpRequest();
+        xmlHttp.onreadystatechange = () => {
+            if (xmlHttp.readyState == 4) {
+                if (xmlHttp.status == 200) {
+                    var snippet = JSON.parse(xmlHttp.responseText);
+                    const oldId = spriteManager.snippetId ;
+                    spriteManager.snippetId = snippet.id;
+                    if (snippet.version && snippet.version != "0") {
+                        spriteManager.snippetId += "#" + snippet.version;
+                    }
+                    this.forceUpdate();
+                    if (navigator.clipboard) {
+                        navigator.clipboard.writeText(spriteManager.snippetId);
+                    }
+
+                    let windowAsAny = window as any;
+
+                    if (windowAsAny.Playground && oldId) {
+                        windowAsAny.Playground.onRequestCodeChangeObservable.notifyObservers({
+                            regex: new RegExp(oldId, "g"),
+                            replace: spriteManager.snippetId
+                        });
+                    }
+
+                    alert("Sprite manager saved with ID: " + spriteManager.snippetId + " (please note that the id was also saved to your clipboard)");
+                }
+                else {
+                    alert("Unable to save your sprite manager");
+                }
+            }
+        }
+
+        xmlHttp.open("POST", this._snippetUrl + (spriteManager.snippetId ? "/" + spriteManager.snippetId : ""), true);
+        xmlHttp.setRequestHeader("Content-Type", "application/json");
+
+        var dataToSend = {
+            payload : JSON.stringify({
+                particleSystem: content
+            }),
+            name: "",
+            description: "",
+            tags: ""
+        };
+
+        xmlHttp.send(JSON.stringify(dataToSend));
+    }
+
     render() {
         const spriteManager = this.props.spriteManager;
 
@@ -70,6 +169,18 @@ export class SpriteManagerPropertyGridComponent extends React.Component<ISpriteM
                     }
                     <ButtonLineComponent label="Dispose" onClick={() => this.disposeManager()} />
                 </LineContainerComponent>
+                <LineContainerComponent globalState={this.props.globalState} title="FILE">
+                    <FileButtonLineComponent label="Load" onClick={(file) => this.loadFromFile(file)} accept=".json" />
+                    <ButtonLineComponent label="Save" onClick={() => this.saveToFile()} />
+                </LineContainerComponent>                
+                <LineContainerComponent globalState={this.props.globalState} title="SNIPPET">
+                    {
+                        spriteManager.snippetId &&
+                        <TextLineComponent label="Snippet ID" value={spriteManager.snippetId} />
+                    }
+                    <ButtonLineComponent label="Load from snippet server" onClick={() => this.loadFromSnippet()} />
+                    <ButtonLineComponent label="Save to snippet server" onClick={() => this.saveToSnippet()} />
+                </LineContainerComponent>  
                 <LineContainerComponent globalState={this.props.globalState} title="PROPERTIES">
                     <CheckBoxLineComponent label="Pickable" target={spriteManager} propertyName="isPickable" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <CheckBoxLineComponent label="Fog enabled" target={spriteManager} propertyName="fogEnabled" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 69 - 3
src/Sprites/sprite.ts

@@ -1,7 +1,7 @@
 import { Vector3 } from "../Maths/math.vector";
 import { Nullable } from "../types";
 import { ActionManager } from "../Actions/actionManager";
-import { ISpriteManager } from "./spriteManager";
+import { ISpriteManager, SpriteManager } from "./spriteManager";
 import { Color4 } from '../Maths/math.color';
 import { Observable } from '../Misc/observable';
 import { IAnimatable } from '../Animations/animatable.interface';
@@ -66,7 +66,7 @@ export class Sprite implements IAnimatable {
     private _direction = 1;
     private _manager: ISpriteManager;
     private _time = 0;
-    private _onAnimationEnd: () => void;
+    private _onAnimationEnd: Nullable<() => void> = null;
     /**
      * Gets or sets a boolean indicating if the sprite is visible (renderable). Default is true
      */
@@ -172,7 +172,7 @@ export class Sprite implements IAnimatable {
      * @param delay defines the start delay (in ms)
      * @param onAnimationEnd defines a callback to call when animation ends
      */
-    public playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: () => void): void {
+    public playAnimation(from: number, to: number, loop: boolean, delay: number, onAnimationEnd: Nullable<() => void> = null): void {
         this._fromIndex = from;
         this._toIndex = to;
         this._loopAnimation = loop;
@@ -237,4 +237,70 @@ export class Sprite implements IAnimatable {
         this.onDisposeObservable.notifyObservers(this);
         this.onDisposeObservable.clear();
     }
+
+    /**
+     * Serializes the sprite to a JSON object
+     * @returns the JSON object
+     */
+    public serialize(): any {
+        var serializationObject: any = {};
+
+        serializationObject.name = this.name;
+        serializationObject.position = this.position.asArray();
+        serializationObject.color = this.color.asArray();
+        serializationObject.width = this.width;
+        serializationObject.height = this.height;
+        serializationObject.angle = this.angle;
+        serializationObject.cellIndex = this.cellIndex;
+        serializationObject.cellRef = this.cellRef;
+        serializationObject.invertU = this.invertU;
+        serializationObject.invertV = this.invertV;
+        serializationObject.disposeWhenFinishedAnimating = this.disposeWhenFinishedAnimating;
+        serializationObject.isPickable = this.isPickable;
+        serializationObject.isVisible = this.isVisible;
+        serializationObject.useAlphaForPicking = this.useAlphaForPicking;
+
+        serializationObject.animationStarted = this.animationStarted;
+        serializationObject.fromIndex = this.fromIndex;
+        serializationObject.toIndex = this.toIndex;
+        serializationObject.loopAnimation = this.loopAnimation;
+        serializationObject.delay = this.delay;
+
+        return serializationObject;
+    }
+
+    /**
+     * Parses a JSON object to create a new sprite
+     * @param parsedSprite The JSON object to parse
+     * @param manager defines the hosting manager
+     * @returns the new sprite
+     */
+    public static Parse(parsedSprite: any, manager: SpriteManager): Sprite {
+        var sprite = new Sprite(parsedSprite.name, manager);
+
+        sprite.position = Vector3.FromArray(parsedSprite.position);
+        sprite.color = Color4.FromArray(parsedSprite.color);
+        sprite.width = parsedSprite.width;
+        sprite.height = parsedSprite.height;
+        sprite.angle = parsedSprite.angle;
+        sprite.cellIndex = parsedSprite.cellIndex;
+        sprite.cellRef = parsedSprite.cellRef;
+        sprite.invertU = parsedSprite.invertU;
+        sprite.invertV = parsedSprite.invertV;
+        sprite.disposeWhenFinishedAnimating = parsedSprite.disposeWhenFinishedAnimating;
+        sprite.isPickable = parsedSprite.isPickable;
+        sprite.isVisible = parsedSprite.isVisible;
+        sprite.useAlphaForPicking = parsedSprite.useAlphaForPicking;
+
+        sprite.fromIndex = parsedSprite.fromIndex;
+        sprite.toIndex = parsedSprite.toIndex;
+        sprite.loopAnimation = parsedSprite.loopAnimation;
+        sprite.delay = parsedSprite.delay;
+
+        if (parsedSprite.animationStarted) {
+            sprite.playAnimation(sprite.fromIndex, sprite.toIndex, sprite.loopAnimation, sprite.delay);
+        }
+
+        return sprite;
+    }
 }

+ 103 - 3
src/Sprites/spriteManager.ts

@@ -19,6 +19,7 @@ import "../Shaders/sprites.fragment";
 import "../Shaders/sprites.vertex";
 import { DataBuffer } from '../Meshes/dataBuffer';
 import { Engine } from '../Engines/engine';
+import { WebRequest } from '../Misc/webRequest';
 declare type Ray = import("../Culling/ray").Ray;
 
 /**
@@ -98,6 +99,12 @@ export interface ISpriteManager extends IDisposable {
  * @see http://doc.babylonjs.com/babylon101/sprites
  */
 export class SpriteManager implements ISpriteManager {
+    /** Define the Url to load snippets */
+    public static SnippetUrl = "https://snippet.babylonjs.com";
+
+    /** Snippet ID if the manager was created from the snippet server */
+    public snippetId: string;
+
     /** Gets the list of sprites */
     public sprites = new Array<Sprite>();
     /** Gets or sets the rendering group id (0 by default) */
@@ -188,6 +195,8 @@ export class SpriteManager implements ISpriteManager {
 
     public set texture(value: Texture) {
         this._spriteTexture = value;
+        this._spriteTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
+        this._spriteTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
         this._textureContent = null;
     }
 
@@ -229,9 +238,12 @@ export class SpriteManager implements ISpriteManager {
         }
         this._capacity = capacity;
         this._fromPacked = fromPacked;
-        this._spriteTexture = new Texture(imgUrl, scene, true, false, samplingMode);
-        this._spriteTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
-        this._spriteTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
+
+        if (imgUrl) {
+            this._spriteTexture = new Texture(imgUrl, scene, true, false, samplingMode);
+            this._spriteTexture.wrapU = Texture.CLAMP_ADDRESSMODE;
+            this._spriteTexture.wrapV = Texture.CLAMP_ADDRESSMODE;
+        }
 
         if (cellSize.width && cellSize.height) {
             this.cellWidth = cellSize.width;
@@ -753,4 +765,92 @@ export class SpriteManager implements ISpriteManager {
         this.onDisposeObservable.notifyObservers(this);
         this.onDisposeObservable.clear();
     }
+
+    /**
+     * Serializes the sprite manager to a JSON object
+     * @param serializeTexture defines if the texture must be serialized as well
+     * @returns the JSON object
+     */
+    public serialize(serializeTexture = false): any {
+        var serializationObject: any = {};
+
+        serializationObject.name = this.name;
+        serializationObject.capacity = this.capacity;
+        serializationObject.cellWidth = this.cellWidth;
+        serializationObject.cellHeight = this.cellHeight;
+
+        if (this.texture) {
+            if (serializeTexture) {
+                serializationObject.texture = this.texture.serialize();
+            } else {
+                serializationObject.textureUrl = this.texture.name;
+                serializationObject.invertY = this.texture._invertY;
+            }
+        }
+
+        serializationObject.sprites = [];
+
+        for (var sprite of this.sprites) {
+            serializationObject.sprites.push(sprite.serialize());
+        }
+
+        return serializationObject;
+    }
+
+    /**
+     * Parses a JSON object to create a new sprite manager.
+     * @param parsedManager The JSON object to parse
+     * @param scene The scene to create the sprite managerin
+     * @param rootUrl The root url to use to load external dependencies like texture
+     * @returns the new sprite manager
+     */
+    public static Parse(parsedManager: any, scene: Scene, rootUrl: string): SpriteManager {
+        var manager = new SpriteManager(parsedManager.name, "", parsedManager.capacity, {
+            width: parsedManager.cellWidth,
+            height: parsedManager.cellHeight,
+        }, scene);
+
+        if (parsedManager.texture) {
+            manager.texture = Texture.Parse(parsedManager.texture, scene, rootUrl) as Texture;
+        } else if (parsedManager.textureName) {
+            manager.texture = new Texture(rootUrl + parsedManager.textureUrl, scene, false, parsedManager.invertY !== undefined ? parsedManager.invertY : true);
+        }
+
+        for (var parsedSprite of parsedManager.sprites) {
+            Sprite.Parse(parsedSprite, manager);
+        }
+
+        return manager;
+    }
+
+    /**
+     * Creates a sprite manager from a snippet saved by the sprite editor
+     * @param snippetId defines the snippet to load
+     * @param scene defines the hosting scene
+     * @param rootUrl defines the root URL to use to load textures and relative dependencies
+     * @returns a promise that will resolve to the new sprite manager
+     */
+    public static CreateFromSnippetAsync(snippetId: string, scene: Scene, rootUrl: string = ""): Promise<SpriteManager> {
+        return new Promise((resolve, reject) => {
+            var request = new WebRequest();
+            request.addEventListener("readystatechange", () => {
+                if (request.readyState == 4) {
+                    if (request.status == 200) {
+                        var snippet = JSON.parse(JSON.parse(request.responseText).jsonPayload);
+                        let serializationObject = JSON.parse(snippet.spriteManager);
+                        let output = SpriteManager.Parse(serializationObject, scene, rootUrl);
+
+                        output.snippetId = snippetId;
+
+                        resolve(output);
+                    } else {
+                        reject("Unable to load the snippet " + snippetId);
+                    }
+                }
+            });
+
+            request.open("GET", this.SnippetUrl + "/" + snippetId.replace(/#/g, "/"));
+            request.send();
+        });
+    }
 }