Sfoglia il codice sorgente

Fixing small bugs with multi-cameras

David Catuhe 9 anni fa
parent
commit
a9970e01d0

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


+ 475 - 337
dist/preview release/babylon.d.ts

@@ -416,6 +416,7 @@ declare module BABYLON {
         uniqueId: number;
         state: string;
         animations: Animation[];
+        private _ranges;
         onReady: (node: Node) => void;
         private _childrenFlag;
         private _isEnabled;
@@ -475,6 +476,12 @@ declare module BABYLON {
         getDescendants(): Node[];
         _setReady(state: boolean): void;
         getAnimationByName(name: string): Animation;
+        createAnimationRange(name: string, from: number, to: number): void;
+        deleteAnimationRange(name: string, deleteFrames?: boolean): void;
+        getAnimationRange(name: string): AnimationRange;
+        beginAnimation(name: string, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void): void;
+        serializeAnimationRanges(): any;
+        static ParseAnimationRanges(node: Node, parsedNode: any, scene: Scene): void;
     }
 }
 
@@ -1310,11 +1317,12 @@ declare module BABYLON {
          */
         removeEvents(frame: number): void;
         createRange(name: string, from: number, to: number): void;
-        deleteRange(name: string): void;
+        deleteRange(name: string, deleteFrames?: boolean): void;
         getRange(name: string): AnimationRange;
         reset(): void;
         isStopped(): boolean;
         getKeys(): any[];
+        getHighestFrame(): number;
         getEasingFunction(): IEasingFunction;
         setEasingFunction(easingFunction: EasingFunction): void;
         floatInterpolateFunction(startValue: number, endValue: number, gradient: number): number;
@@ -1621,6 +1629,7 @@ declare module BABYLON {
         updateMatrix(matrix: Matrix): void;
         private _updateDifferenceMatrix();
         markAsDirty(): void;
+        copyAnimationRange(source: Bone, rangeName: string, frameOffset: number, rescaleAsRequired?: boolean): boolean;
     }
 }
 
@@ -1639,8 +1648,13 @@ declare module BABYLON {
         getTransformMatrices(): Float32Array;
         getScene(): Scene;
         createAnimationRange(name: string, from: number, to: number): void;
-        deleteAnimationRange(name: string): void;
+        deleteAnimationRange(name: string, deleteFrames?: boolean): void;
         getAnimationRange(name: string): AnimationRange;
+        /**
+         *  note: This is not for a complete retargeting, only between very similar skeleton's with only possible bone length differences
+         */
+        copyAnimationRange(source: Skeleton, name: string, rescaleAsRequired?: boolean): boolean;
+        private _getHighestAnimationFrame();
         beginAnimation(name: string, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void): void;
         _markAsDirty(): void;
         prepare(): void;
@@ -2052,6 +2066,63 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    class DebugLayer {
+        private _scene;
+        private _camera;
+        private _transformationMatrix;
+        private _enabled;
+        private _labelsEnabled;
+        private _displayStatistics;
+        private _displayTree;
+        private _displayLogs;
+        private _globalDiv;
+        private _statsDiv;
+        private _statsSubsetDiv;
+        private _optionsDiv;
+        private _optionsSubsetDiv;
+        private _logDiv;
+        private _logSubsetDiv;
+        private _treeDiv;
+        private _treeSubsetDiv;
+        private _drawingCanvas;
+        private _drawingContext;
+        private _rootElement;
+        _syncPositions: () => void;
+        private _syncData;
+        private _syncUI;
+        private _onCanvasClick;
+        private _clickPosition;
+        private _ratio;
+        private _identityMatrix;
+        private _showUI;
+        private _needToRefreshMeshesTree;
+        shouldDisplayLabel: (node: Node) => boolean;
+        shouldDisplayAxis: (mesh: Mesh) => boolean;
+        axisRatio: number;
+        accentColor: string;
+        customStatsFunction: () => string;
+        constructor(scene: Scene);
+        private _refreshMeshesTreeContent();
+        private _renderSingleAxis(zero, unit, unitText, label, color);
+        private _renderAxis(projectedPosition, mesh, globalViewport);
+        private _renderLabel(text, projectedPosition, labelOffset, onClick, getFillStyle);
+        private _isClickInsideRect(x, y, width, height);
+        isVisible(): boolean;
+        hide(): void;
+        show(showUI?: boolean, camera?: Camera, rootElement?: HTMLElement): void;
+        private _clearLabels();
+        private _generateheader(root, text);
+        private _generateTexBox(root, title, color);
+        private _generateAdvancedCheckBox(root, leftTitle, rightTitle, initialState, task, tag?);
+        private _generateCheckBox(root, title, initialState, task, tag?);
+        private _generateButton(root, title, task, tag?);
+        private _generateRadio(root, title, name, initialState, task, tag?);
+        private _generateDOMelements();
+        private _displayStats();
+    }
+}
+
+declare module BABYLON {
     class Collider {
         radius: Vector3;
         retry: number;
@@ -2293,6 +2364,26 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    class Layer {
+        name: string;
+        texture: Texture;
+        isBackground: boolean;
+        color: Color4;
+        onDispose: () => void;
+        alphaBlendingMode: number;
+        private _scene;
+        private _vertexDeclaration;
+        private _vertexStrideSize;
+        private _vertexBuffer;
+        private _indexBuffer;
+        private _effect;
+        constructor(name: string, imgUrl: string, scene: Scene, isBackground?: boolean, color?: Color4);
+        render(): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
     class BoundingBox {
         minimum: Vector3;
         maximum: Vector3;
@@ -2353,83 +2444,6 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
-    class DebugLayer {
-        private _scene;
-        private _camera;
-        private _transformationMatrix;
-        private _enabled;
-        private _labelsEnabled;
-        private _displayStatistics;
-        private _displayTree;
-        private _displayLogs;
-        private _globalDiv;
-        private _statsDiv;
-        private _statsSubsetDiv;
-        private _optionsDiv;
-        private _optionsSubsetDiv;
-        private _logDiv;
-        private _logSubsetDiv;
-        private _treeDiv;
-        private _treeSubsetDiv;
-        private _drawingCanvas;
-        private _drawingContext;
-        private _rootElement;
-        _syncPositions: () => void;
-        private _syncData;
-        private _syncUI;
-        private _onCanvasClick;
-        private _clickPosition;
-        private _ratio;
-        private _identityMatrix;
-        private _showUI;
-        private _needToRefreshMeshesTree;
-        shouldDisplayLabel: (node: Node) => boolean;
-        shouldDisplayAxis: (mesh: Mesh) => boolean;
-        axisRatio: number;
-        accentColor: string;
-        customStatsFunction: () => string;
-        constructor(scene: Scene);
-        private _refreshMeshesTreeContent();
-        private _renderSingleAxis(zero, unit, unitText, label, color);
-        private _renderAxis(projectedPosition, mesh, globalViewport);
-        private _renderLabel(text, projectedPosition, labelOffset, onClick, getFillStyle);
-        private _isClickInsideRect(x, y, width, height);
-        isVisible(): boolean;
-        hide(): void;
-        show(showUI?: boolean, camera?: Camera, rootElement?: HTMLElement): void;
-        private _clearLabels();
-        private _generateheader(root, text);
-        private _generateTexBox(root, title, color);
-        private _generateAdvancedCheckBox(root, leftTitle, rightTitle, initialState, task, tag?);
-        private _generateCheckBox(root, title, initialState, task, tag?);
-        private _generateButton(root, title, task, tag?);
-        private _generateRadio(root, title, name, initialState, task, tag?);
-        private _generateDOMelements();
-        private _displayStats();
-    }
-}
-
-declare module BABYLON {
-    class Layer {
-        name: string;
-        texture: Texture;
-        isBackground: boolean;
-        color: Color4;
-        onDispose: () => void;
-        alphaBlendingMode: number;
-        private _scene;
-        private _vertexDeclaration;
-        private _vertexStrideSize;
-        private _vertexBuffer;
-        private _indexBuffer;
-        private _effect;
-        constructor(name: string, imgUrl: string, scene: Scene, isBackground?: boolean, color?: Color4);
-        render(): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
     class LensFlare {
         size: number;
         position: number;
@@ -2600,38 +2614,6 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
-    interface ISceneLoaderPlugin {
-        extensions: string;
-        importMesh: (meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => boolean;
-        load: (scene: Scene, data: string, rootUrl: string) => boolean;
-    }
-    class SceneLoader {
-        private static _ForceFullSceneLoadingForIncremental;
-        private static _ShowLoadingScreen;
-        static ForceFullSceneLoadingForIncremental: boolean;
-        static ShowLoadingScreen: boolean;
-        private static _registeredPlugins;
-        private static _getPluginForFilename(sceneFilename);
-        static RegisterPlugin(plugin: ISceneLoaderPlugin): void;
-        static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene, e: any) => void): void;
-        /**
-        * Load a scene
-        * @param rootUrl a string that defines the root url for scene and resources
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
-        * @param engine is the instance of BABYLON.Engine to use to create the scene
-        */
-        static Load(rootUrl: string, sceneFilename: any, engine: Engine, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void;
-        /**
-        * Append a scene
-        * @param rootUrl a string that defines the root url for scene and resources
-        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
-        * @param scene is the instance of BABYLON.Scene to append to
-        */
-        static Append(rootUrl: string, sceneFilename: any, scene: Scene, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void;
-    }
-}
-
-declare module BABYLON {
     class EffectFallbacks {
         private _defines;
         private _currentRank;
@@ -2907,6 +2889,38 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    interface ISceneLoaderPlugin {
+        extensions: string;
+        importMesh: (meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => boolean;
+        load: (scene: Scene, data: string, rootUrl: string) => boolean;
+    }
+    class SceneLoader {
+        private static _ForceFullSceneLoadingForIncremental;
+        private static _ShowLoadingScreen;
+        static ForceFullSceneLoadingForIncremental: boolean;
+        static ShowLoadingScreen: boolean;
+        private static _registeredPlugins;
+        private static _getPluginForFilename(sceneFilename);
+        static RegisterPlugin(plugin: ISceneLoaderPlugin): void;
+        static ImportMesh(meshesNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onsuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, progressCallBack?: () => void, onerror?: (scene: Scene, e: any) => void): void;
+        /**
+        * Load a scene
+        * @param rootUrl a string that defines the root url for scene and resources
+        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+        * @param engine is the instance of BABYLON.Engine to use to create the scene
+        */
+        static Load(rootUrl: string, sceneFilename: any, engine: Engine, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void;
+        /**
+        * Append a scene
+        * @param rootUrl a string that defines the root url for scene and resources
+        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+        * @param scene is the instance of BABYLON.Scene to append to
+        */
+        static Append(rootUrl: string, sceneFilename: any, scene: Scene, onsuccess?: (scene: Scene) => void, progressCallBack?: any, onerror?: (scene: Scene) => void): void;
+    }
+}
+
+declare module BABYLON {
     class SIMDVector3 {
         static TransformCoordinatesToRefSIMD(vector: Vector3, transformation: Matrix, result: Vector3): void;
         static TransformCoordinatesFromFloatsToRefSIMD(x: number, y: number, z: number, transformation: Matrix, result: Vector3): void;
@@ -3105,7 +3119,7 @@ declare module BABYLON {
         static DistanceSquared(value1: Vector3, value2: Vector3): number;
         static Center(value1: Vector3, value2: Vector3): Vector3;
         /**
-         * Given three orthogonal left-handed oriented Vector3 axis in space (target system),
+         * Given three orthogonal normalized left-handed oriented Vector3 axis in space (target system),
          * RotationFromAxis() returns the rotation Euler angles (ex : rotation.x, rotation.y, rotation.z) to apply
          * to something in order to rotate it from its local system to the given target system.
          */
@@ -3441,6 +3455,334 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    class Particle {
+        position: Vector3;
+        direction: Vector3;
+        color: Color4;
+        colorStep: Color4;
+        lifeTime: number;
+        age: number;
+        size: number;
+        angle: number;
+        angularSpeed: number;
+        copyTo(other: Particle): void;
+    }
+}
+
+declare module BABYLON {
+    class ParticleSystem implements IDisposable {
+        name: string;
+        static BLENDMODE_ONEONE: number;
+        static BLENDMODE_STANDARD: number;
+        id: string;
+        renderingGroupId: number;
+        emitter: any;
+        emitRate: number;
+        manualEmitCount: number;
+        updateSpeed: number;
+        targetStopDuration: number;
+        disposeOnStop: boolean;
+        minEmitPower: number;
+        maxEmitPower: number;
+        minLifeTime: number;
+        maxLifeTime: number;
+        minSize: number;
+        maxSize: number;
+        minAngularSpeed: number;
+        maxAngularSpeed: number;
+        particleTexture: Texture;
+        layerMask: number;
+        onDispose: () => void;
+        updateFunction: (particles: Particle[]) => void;
+        blendMode: number;
+        forceDepthWrite: boolean;
+        gravity: Vector3;
+        direction1: Vector3;
+        direction2: Vector3;
+        minEmitBox: Vector3;
+        maxEmitBox: Vector3;
+        color1: Color4;
+        color2: Color4;
+        colorDead: Color4;
+        textureMask: Color4;
+        startDirectionFunction: (emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle) => void;
+        startPositionFunction: (worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle) => void;
+        private particles;
+        private _capacity;
+        private _scene;
+        private _vertexDeclaration;
+        private _vertexStrideSize;
+        private _stockParticles;
+        private _newPartsExcess;
+        private _vertexBuffer;
+        private _indexBuffer;
+        private _vertices;
+        private _effect;
+        private _customEffect;
+        private _cachedDefines;
+        private _scaledColorStep;
+        private _colorDiff;
+        private _scaledDirection;
+        private _scaledGravity;
+        private _currentRenderId;
+        private _alive;
+        private _started;
+        private _stopped;
+        private _actualFrame;
+        private _scaledUpdateSpeed;
+        constructor(name: string, capacity: number, scene: Scene, customEffect?: Effect);
+        recycleParticle(particle: Particle): void;
+        getCapacity(): number;
+        isAlive(): boolean;
+        isStarted(): boolean;
+        start(): void;
+        stop(): void;
+        _appendParticleVertex(index: number, particle: Particle, offsetX: number, offsetY: number): void;
+        private _update(newParticles);
+        private _getEffect();
+        animate(): void;
+        render(): number;
+        dispose(): void;
+        clone(name: string, newEmitter: any): ParticleSystem;
+        serialize(): any;
+        static Parse(parsedParticleSystem: any, scene: Scene, rootUrl: string): ParticleSystem;
+    }
+}
+
+declare module BABYLON {
+    class SolidParticle {
+        idx: number;
+        color: Color4;
+        position: Vector3;
+        rotation: Vector3;
+        quaternion: Vector4;
+        scale: Vector3;
+        uvs: Vector4;
+        velocity: Vector3;
+        alive: boolean;
+        _pos: number;
+        _model: ModelShape;
+        shapeId: number;
+        idxInShape: number;
+        constructor(particleIndex: number, positionIndex: number, model: ModelShape, shapeId: number, idxInShape: number);
+    }
+    class ModelShape {
+        shapeID: number;
+        _shape: Vector3[];
+        _shapeUV: number[];
+        _positionFunction: (particle: SolidParticle, i: number, s: number) => void;
+        _vertexFunction: (particle: SolidParticle, vertex: Vector3, i: number) => void;
+        constructor(id: number, shape: Vector3[], shapeUV: number[], posFunction: (particle: SolidParticle, i: number, s: number) => void, vtxFunction: (particle: SolidParticle, vertex: Vector3, i: number) => void);
+    }
+}
+
+declare module BABYLON {
+    /**
+    * Full documentation here : http://doc.babylonjs.com/tutorials/Solid_Particle_System
+    */
+    class SolidParticleSystem implements IDisposable {
+        particles: SolidParticle[];
+        nbParticles: number;
+        billboard: boolean;
+        counter: number;
+        name: string;
+        mesh: Mesh;
+        vars: any;
+        pickedParticles: {
+            idx: number;
+            faceId: number;
+        }[];
+        private _scene;
+        private _positions;
+        private _indices;
+        private _normals;
+        private _colors;
+        private _uvs;
+        private _positions32;
+        private _normals32;
+        private _fixedNormal32;
+        private _colors32;
+        private _uvs32;
+        private _index;
+        private _updatable;
+        private _pickable;
+        private _alwaysVisible;
+        private _shapeCounter;
+        private _copy;
+        private _shape;
+        private _shapeUV;
+        private _color;
+        private _computeParticleColor;
+        private _computeParticleTexture;
+        private _computeParticleRotation;
+        private _computeParticleVertex;
+        private _cam_axisZ;
+        private _cam_axisY;
+        private _cam_axisX;
+        private _axisX;
+        private _axisY;
+        private _axisZ;
+        private _camera;
+        private _particle;
+        private _fakeCamPos;
+        private _rotMatrix;
+        private _invertMatrix;
+        private _rotated;
+        private _quaternion;
+        private _vertex;
+        private _normal;
+        private _yaw;
+        private _pitch;
+        private _roll;
+        private _halfroll;
+        private _halfpitch;
+        private _halfyaw;
+        private _sinRoll;
+        private _cosRoll;
+        private _sinPitch;
+        private _cosPitch;
+        private _sinYaw;
+        private _cosYaw;
+        private _w;
+        /**
+        * Creates a SPS (Solid Particle System) object.
+        * @param name the SPS name, this will be the underlying mesh name
+        * @param updatable (default true) if the SPS must be updatable or immutable
+        * @param isPickable (default false) if the solid particles must be pickable
+        */
+        constructor(name: string, scene: Scene, options?: {
+            updatable?: boolean;
+            isPickable?: boolean;
+        });
+        /**
+        * Builds the SPS underlying mesh. Returns a standard Mesh.
+        * If no model shape was added to the SPS, the return mesh is only a single triangular plane.
+        */
+        buildMesh(): Mesh;
+        private _resetCopy();
+        private _meshBuilder(p, shape, positions, meshInd, indices, meshUV, uvs, meshCol, colors, idx, idxInShape, options);
+        private _posToShape(positions);
+        private _uvsToShapeUV(uvs);
+        private _addParticle(idx, idxpos, model, shapeId, idxInShape);
+        /**
+        * Adds some particles to the SPS from the model shape.
+        * Please read the doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#create-an-immutable-sps
+        * @param mesh any Mesh object that will be used as a model for the solid particles.
+        * @param nb the number of particles to be created from this model
+        * @param positionFunction an optional javascript function to called for each particle on SPS creation
+        * @param vertexFunction an optional javascript function to called for each vertex of each particle on SPS creation
+        */
+        addShape(mesh: Mesh, nb: number, options?: {
+            positionFunction?: any;
+            vertexFunction?: any;
+        }): number;
+        private _rebuildParticle(particle);
+        /**
+        * Rebuilds the whole mesh and updates the VBO : custom positions and vertices are recomputed if needed.
+        */
+        rebuildMesh(): void;
+        /**
+        *  Sets all the particles : this method actually really updates the mesh according to the particle positions, rotations, colors, textures, etc.
+        *  This method calls updateParticle() for each particles of the SPS.
+        *  For an animated SPS, it is usually called within the render loop.
+        * @param start (default 0) the particle index in the particle array where to start to compute the particle property values
+        * @param end (default nbParticle - 1)  the particle index in the particle array where to stop to compute the particle property values
+        * @param update (default true) if the mesh must be finally updated on this call after all the particle computations.
+        */
+        setParticles(start?: number, end?: number, update?: boolean): void;
+        private _quaternionRotationYPR();
+        private _quaternionToRotationMatrix();
+        /**
+        * Disposes the SPS
+        */
+        dispose(): void;
+        /**
+        *  Visibilty helper : Recomputes the visible size according to the mesh bounding box
+        * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#sps-visibility
+        */
+        refreshVisibleSize(): void;
+        /**
+        * True if the SPS is set as always visible
+        */
+        /**
+        * Sets the SPS as always visible or not
+        * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#sps-visibility
+        */
+        isAlwaysVisible: boolean;
+        /**
+        * Tells to setParticle() to compute the particle rotations or not.
+        * Default value : true. The SPS is faster when it's set to false.
+        * Note : the particle rotations aren't stored values, so setting computeParticleRotation to false will prevents the particle to rotate.
+        */
+        computeParticleRotation: boolean;
+        /**
+        * Tells to setParticle() to compute the particle colors or not.
+        * Default value : true. The SPS is faster when it's set to false.
+        * Note : the particle colors are stored values, so setting computeParticleColor to false will keep yet the last colors set.
+        */
+        computeParticleColor: boolean;
+        /**
+        * Tells to setParticle() to compute the particle textures or not.
+        * Default value : true. The SPS is faster when it's set to false.
+        * Note : the particle textures are stored values, so setting computeParticleTexture to false will keep yet the last colors set.
+        */
+        computeParticleTexture: boolean;
+        /**
+        * Tells to setParticle() to call the vertex function for each vertex of each particle, or not.
+        * Default value : false. The SPS is faster when it's set to false.
+        * Note : the particle custom vertex positions aren't stored values.
+        */
+        computeParticleVertex: boolean;
+        /**
+        * This function does nothing. It may be overwritten to set all the particles first values.
+        * The SPS doesn't call this function, you may have to call it by your own.
+        * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#particle-management
+        */
+        initParticles(): void;
+        /**
+        * This function does nothing. It may be overwritten to recycle a particle.
+        * The SPS doesn't call this function, you may have to call it by your own.
+        * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#particle-management
+        */
+        recycleParticle(particle: SolidParticle): SolidParticle;
+        /**
+        * Updates a particle : this function should  be overwritten by the user.
+        * It is called on each particle by setParticles(). This is the place to code each particle behavior.
+        * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#particle-management
+        * ex : just set a particle position or velocity and recycle conditions
+        */
+        updateParticle(particle: SolidParticle): SolidParticle;
+        /**
+        * Updates a vertex of a particle : it can be overwritten by the user.
+        * This will be called on each vertex particle by setParticles() if computeParticleVertex is set to true only.
+        * @param particle the current particle
+        * @param vertex the current index of the current particle
+        * @param pt the index of the current vertex in the particle shape
+        * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#update-each-particle-shape
+        * ex : just set a vertex particle position
+        */
+        updateParticleVertex(particle: SolidParticle, vertex: Vector3, pt: number): Vector3;
+        /**
+        * This will be called before any other treatment by setParticles() and will be passed three parameters.
+        * This does nothing and may be overwritten by the user.
+        * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+        * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+        * @param update the boolean update value actually passed to setParticles()
+        */
+        beforeUpdateParticles(start?: number, stop?: number, update?: boolean): void;
+        /**
+        * This will be called  by setParticles() after all the other treatments and just before the actual mesh update.
+        * This will be passed three parameters.
+        * This does nothing and may be overwritten by the user.
+        * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+        * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+        * @param update the boolean update value actually passed to setParticles()
+        */
+        afterUpdateParticles(start?: number, stop?: number, update?: boolean): void;
+    }
+}
+
+declare module BABYLON {
     class AbstractMesh extends Node implements IDisposable {
         private static _BILLBOARDMODE_NONE;
         private static _BILLBOARDMODE_X;
@@ -3877,8 +4219,26 @@ declare module BABYLON {
         constructor(name: string, scene: Scene);
         subdivisions: number;
         optimize(chunksCount: number, octreeBlocksSize?: number): void;
+        /**
+         * Returns a height (y) value in the Worl system :
+         * the ground altitude at the coordinates (x, z) expressed in the World system.
+         * Returns the ground y position if (x, z) are outside the ground surface.
+         * Not pertinent if the ground is rotated.
+         */
         getHeightAtCoordinates(x: number, z: number): number;
+        /**
+         * Returns a normalized vector (Vector3) orthogonal to the ground
+         * at the ground coordinates (x, z) expressed in the World system.
+         * Returns Vector3(0, 1, 0) if (x, z) are outside the ground surface.
+         * Not pertinent if the ground is rotated.
+         */
         getNormalAtCoordinates(x: number, z: number): Vector3;
+        /**
+         * Updates the Vector3 passed a reference with a normalized vector orthogonal to the ground
+         * at the ground coordinates (x, z) expressed in the World system.
+         * Doesn't uptade the reference Vector3 if (x, z) are outside the ground surface.
+         * Not pertinent if the ground is rotated.
+         */
         getNormalAtCoordinatesToRef(x: number, z: number, ref: Vector3): void;
         private _getFacetAt(x, z);
         private _computeHeightQuads();
@@ -4769,228 +5129,6 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
-    class Particle {
-        position: Vector3;
-        direction: Vector3;
-        color: Color4;
-        colorStep: Color4;
-        lifeTime: number;
-        age: number;
-        size: number;
-        angle: number;
-        angularSpeed: number;
-        copyTo(other: Particle): void;
-    }
-}
-
-declare module BABYLON {
-    class ParticleSystem implements IDisposable {
-        name: string;
-        static BLENDMODE_ONEONE: number;
-        static BLENDMODE_STANDARD: number;
-        id: string;
-        renderingGroupId: number;
-        emitter: any;
-        emitRate: number;
-        manualEmitCount: number;
-        updateSpeed: number;
-        targetStopDuration: number;
-        disposeOnStop: boolean;
-        minEmitPower: number;
-        maxEmitPower: number;
-        minLifeTime: number;
-        maxLifeTime: number;
-        minSize: number;
-        maxSize: number;
-        minAngularSpeed: number;
-        maxAngularSpeed: number;
-        particleTexture: Texture;
-        layerMask: number;
-        onDispose: () => void;
-        updateFunction: (particles: Particle[]) => void;
-        blendMode: number;
-        forceDepthWrite: boolean;
-        gravity: Vector3;
-        direction1: Vector3;
-        direction2: Vector3;
-        minEmitBox: Vector3;
-        maxEmitBox: Vector3;
-        color1: Color4;
-        color2: Color4;
-        colorDead: Color4;
-        textureMask: Color4;
-        startDirectionFunction: (emitPower: number, worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle) => void;
-        startPositionFunction: (worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle) => void;
-        private particles;
-        private _capacity;
-        private _scene;
-        private _vertexDeclaration;
-        private _vertexStrideSize;
-        private _stockParticles;
-        private _newPartsExcess;
-        private _vertexBuffer;
-        private _indexBuffer;
-        private _vertices;
-        private _effect;
-        private _customEffect;
-        private _cachedDefines;
-        private _scaledColorStep;
-        private _colorDiff;
-        private _scaledDirection;
-        private _scaledGravity;
-        private _currentRenderId;
-        private _alive;
-        private _started;
-        private _stopped;
-        private _actualFrame;
-        private _scaledUpdateSpeed;
-        constructor(name: string, capacity: number, scene: Scene, customEffect?: Effect);
-        recycleParticle(particle: Particle): void;
-        getCapacity(): number;
-        isAlive(): boolean;
-        isStarted(): boolean;
-        start(): void;
-        stop(): void;
-        _appendParticleVertex(index: number, particle: Particle, offsetX: number, offsetY: number): void;
-        private _update(newParticles);
-        private _getEffect();
-        animate(): void;
-        render(): number;
-        dispose(): void;
-        clone(name: string, newEmitter: any): ParticleSystem;
-        serialize(): any;
-        static Parse(parsedParticleSystem: any, scene: Scene, rootUrl: string): ParticleSystem;
-    }
-}
-
-declare module BABYLON {
-    class SolidParticle {
-        idx: number;
-        color: Color4;
-        position: Vector3;
-        rotation: Vector3;
-        quaternion: Vector4;
-        scale: Vector3;
-        uvs: Vector4;
-        velocity: Vector3;
-        alive: boolean;
-        _pos: number;
-        _model: ModelShape;
-        shapeId: number;
-        idxInShape: number;
-        constructor(particleIndex: number, positionIndex: number, model: ModelShape, shapeId: number, idxInShape: number);
-    }
-    class ModelShape {
-        shapeID: number;
-        _shape: Vector3[];
-        _shapeUV: number[];
-        _positionFunction: (particle: SolidParticle, i: number, s: number) => void;
-        _vertexFunction: (particle: SolidParticle, vertex: Vector3, i: number) => void;
-        constructor(id: number, shape: Vector3[], shapeUV: number[], posFunction: (particle: SolidParticle, i: number, s: number) => void, vtxFunction: (particle: SolidParticle, vertex: Vector3, i: number) => void);
-    }
-}
-
-declare module BABYLON {
-    class SolidParticleSystem implements IDisposable {
-        particles: SolidParticle[];
-        nbParticles: number;
-        billboard: boolean;
-        counter: number;
-        name: string;
-        mesh: Mesh;
-        vars: any;
-        pickedParticles: {
-            idx: number;
-            faceId: number;
-        }[];
-        private _scene;
-        private _positions;
-        private _indices;
-        private _normals;
-        private _colors;
-        private _uvs;
-        private _positions32;
-        private _normals32;
-        private _fixedNormal32;
-        private _colors32;
-        private _uvs32;
-        private _index;
-        private _updatable;
-        private _pickable;
-        private _alwaysVisible;
-        private _shapeCounter;
-        private _copy;
-        private _shape;
-        private _shapeUV;
-        private _color;
-        private _computeParticleColor;
-        private _computeParticleTexture;
-        private _computeParticleRotation;
-        private _computeParticleVertex;
-        private _cam_axisZ;
-        private _cam_axisY;
-        private _cam_axisX;
-        private _axisX;
-        private _axisY;
-        private _axisZ;
-        private _camera;
-        private _particle;
-        private _fakeCamPos;
-        private _rotMatrix;
-        private _invertMatrix;
-        private _rotated;
-        private _quaternion;
-        private _vertex;
-        private _normal;
-        private _yaw;
-        private _pitch;
-        private _roll;
-        private _halfroll;
-        private _halfpitch;
-        private _halfyaw;
-        private _sinRoll;
-        private _cosRoll;
-        private _sinPitch;
-        private _cosPitch;
-        private _sinYaw;
-        private _cosYaw;
-        private _w;
-        constructor(name: string, scene: Scene, options?: {
-            updatable?: boolean;
-            isPickable?: boolean;
-        });
-        buildMesh(): Mesh;
-        private _resetCopy();
-        private _meshBuilder(p, shape, positions, meshInd, indices, meshUV, uvs, meshCol, colors, idx, idxInShape, options);
-        private _posToShape(positions);
-        private _uvsToShapeUV(uvs);
-        private _addParticle(idx, idxpos, model, shapeId, idxInShape);
-        addShape(mesh: Mesh, nb: number, options?: {
-            positionFunction?: any;
-            vertexFunction?: any;
-        }): number;
-        private _rebuildParticle(particle);
-        rebuildMesh(): void;
-        setParticles(start?: number, end?: number, update?: boolean): void;
-        private _quaternionRotationYPR();
-        private _quaternionToRotationMatrix();
-        dispose(): void;
-        refreshVisibleSize(): void;
-        isAlwaysVisible: boolean;
-        computeParticleRotation: boolean;
-        computeParticleColor: boolean;
-        computeParticleTexture: boolean;
-        computeParticleVertex: boolean;
-        initParticles(): void;
-        recycleParticle(particle: SolidParticle): SolidParticle;
-        updateParticle(particle: SolidParticle): SolidParticle;
-        updateParticleVertex(particle: SolidParticle, vertex: Vector3, pt: number): Vector3;
-        beforeUpdateParticles(start?: number, stop?: number, update?: boolean): void;
-        afterUpdateParticles(start?: number, stop?: number, update?: boolean): void;
-    }
-}
-
-declare module BABYLON {
     interface IPhysicsEnginePlugin {
         name: string;
         initialize(iterations?: number): any;
@@ -6613,9 +6751,6 @@ declare module BABYLON {
     }
 }
 
-declare module BABYLON.Internals {
-}
-
 declare module BABYLON {
     class BaseTexture {
         name: string;
@@ -6823,6 +6958,9 @@ declare module BABYLON {
     }
 }
 
+declare module BABYLON.Internals {
+}
+
 declare module BABYLON {
     class CannonJSPlugin implements IPhysicsEnginePlugin {
         private _world;

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


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


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


+ 42 - 13
src/Animations/babylon.animation.js

@@ -35,7 +35,7 @@ var BABYLON;
             // The set of event that will be linked to this animation
             this._events = new Array();
             this.allowMatricesInterpolation = false;
-            this._ranges = new Array();
+            this._ranges = {};
             this.targetPropertyPath = targetProperty.split(".");
             this.dataType = dataType;
             this.loopMode = loopMode === undefined ? Animation.ANIMATIONLOOPMODE_CYCLE : loopMode;
@@ -99,23 +99,29 @@ var BABYLON;
             }
         };
         Animation.prototype.createRange = function (name, from, to) {
-            this._ranges.push(new AnimationRange(name, from, to));
+            // check name not already in use; could happen for bones after serialized
+            if (!this._ranges[name]) {
+                this._ranges[name] = new AnimationRange(name, from, to);
+            }
         };
-        Animation.prototype.deleteRange = function (name) {
-            for (var index = 0; index < this._ranges.length; index++) {
-                if (this._ranges[index].name === name) {
-                    this._ranges.splice(index, 1);
-                    return;
+        Animation.prototype.deleteRange = function (name, deleteFrames) {
+            if (deleteFrames === void 0) { deleteFrames = true; }
+            if (this._ranges[name]) {
+                if (deleteFrames) {
+                    var from = this._ranges[name].from;
+                    var to = this._ranges[name].to;
+                    // this loop MUST go high to low for multiple splices to work
+                    for (var key = this._keys.length - 1; key >= 0; key--) {
+                        if (this._keys[key].frame >= from && this._keys[key].frame <= to) {
+                            this._keys.splice(key, 1);
+                        }
+                    }
                 }
+                this._ranges[name] = undefined; // said much faster than 'delete this._range[name]' 
             }
         };
         Animation.prototype.getRange = function (name) {
-            for (var index = 0; index < this._ranges.length; index++) {
-                if (this._ranges[index].name === name) {
-                    return this._ranges[index];
-                }
-            }
-            return null;
+            return this._ranges[name];
         };
         Animation.prototype.reset = function () {
             this._offsetsCache = {};
@@ -128,6 +134,15 @@ var BABYLON;
         Animation.prototype.getKeys = function () {
             return this._keys;
         };
+        Animation.prototype.getHighestFrame = function () {
+            var ret = 0;
+            for (var key = 0, nKeys = this._keys.length; key < nKeys; key++) {
+                if (ret < this._keys[key].frame) {
+                    ret = this._keys[key].frame;
+                }
+            }
+            return ret;
+        };
         Animation.prototype.getEasingFunction = function () {
             return this._easingFunction;
         };
@@ -430,6 +445,14 @@ var BABYLON;
                 }
                 serializationObject.keys.push(key);
             }
+            serializationObject.ranges = [];
+            for (var name in this._ranges) {
+                var range = {};
+                range.name = name;
+                range.from = this._ranges[name].from;
+                range.to = this._ranges[name].to;
+                serializationObject.ranges.push(range);
+            }
             return serializationObject;
         };
         Object.defineProperty(Animation, "ANIMATIONTYPE_FLOAT", {
@@ -526,6 +549,12 @@ var BABYLON;
                 });
             }
             animation.setKeys(keys);
+            if (parsedAnimation.ranges) {
+                for (var index = 0; index < parsedAnimation.ranges.length; index++) {
+                    data = parsedAnimation.ranges[index];
+                    animation.createRange(data.name, data.from, data.to);
+                }
+            }
             return animation;
         };
         Animation.AppendSerializedAnimations = function (source, destination) {

+ 19 - 18
src/Animations/babylon.animation.ts

@@ -29,7 +29,7 @@
 
         public allowMatricesInterpolation = false;
 
-        private _ranges : { [name: string] : AnimationRange; } = {};
+        private _ranges: { [name: string]: AnimationRange; } = {};
 
         static _PrepareAnimation(targetProperty: string, framePerSecond: number, totalFrame: number,
             from: any, to: any, loopMode?: number, easingFunction?: EasingFunction): Animation {
@@ -114,21 +114,21 @@
 
         public createRange(name: string, from: number, to: number): void {
             // check name not already in use; could happen for bones after serialized
-            if (! this._ranges[name]){
+            if (!this._ranges[name]) {
                 this._ranges[name] = new AnimationRange(name, from, to);
             }
         }
 
         public deleteRange(name: string, deleteFrames = true): void {
-            if (this._ranges[name]){
+            if (this._ranges[name]) {
                 if (deleteFrames) {
                     var from = this._ranges[name].from;
                     var to = this._ranges[name].to;
  
                     // this loop MUST go high to low for multiple splices to work
                     for (var key = this._keys.length - 1; key >= 0; key--) {
-                        if (this._keys[key].frame >= from  && this._keys[key].frame <= to) {
-                           this._keys.splice(key, 1); 
+                        if (this._keys[key].frame >= from && this._keys[key].frame <= to) {
+                            this._keys.splice(key, 1);
                         }
                     }
                 }
@@ -153,13 +153,13 @@
         public getKeys(): any[] {
             return this._keys;
         }
-        
-        public getHighestFrame() : number {
-            var ret = 0; 
-        
+
+        public getHighestFrame(): number {
+            var ret = 0;
+
             for (var key = 0, nKeys = this._keys.length; key < nKeys; key++) {
                 if (ret < this._keys[key].frame) {
-                    ret = this._keys[key].frame; 
+                    ret = this._keys[key].frame;
                 }
             }
             return ret;
@@ -514,13 +514,13 @@
 
                 serializationObject.keys.push(key);
             }
-            
+
             serializationObject.ranges = [];
             for (var name in this._ranges) {
                 var range: any = {};
                 range.name = name;
                 range.from = this._ranges[name].from;
-                range.to   = this._ranges[name].to;
+                range.to = this._ranges[name].to;
                 serializationObject.ranges.push(range);
             }
 
@@ -610,12 +610,12 @@
             }
 
             animation.setKeys(keys);
-            
-            if (parsedAnimation.ranges){
-               for (var index = 0; index < parsedAnimation.ranges.length; index++) {
-                   data = parsedAnimation.ranges[index];
-                   animation.createRange(data.name, data.from, data.to);
-               }
+
+            if (parsedAnimation.ranges) {
+                for (var index = 0; index < parsedAnimation.ranges.length; index++) {
+                    data = parsedAnimation.ranges[index];
+                    animation.createRange(data.name, data.from, data.to);
+                }
             }
 
             return animation;
@@ -635,3 +635,4 @@
 } 
 
 
+

+ 42 - 0
src/Bones/babylon.bone.js

@@ -75,6 +75,48 @@ var BABYLON;
             this._currentRenderId++;
             this._skeleton._markAsDirty();
         };
+        Bone.prototype.copyAnimationRange = function (source, rangeName, frameOffset, rescaleAsRequired) {
+            if (rescaleAsRequired === void 0) { rescaleAsRequired = false; }
+            // all animation may be coming from a library skeleton, so may need to create animation
+            if (this.animations.length === 0) {
+                this.animations.push(new BABYLON.Animation(this.name, "_matrix", source.animations[0].framePerSecond, BABYLON.Animation.ANIMATIONTYPE_MATRIX, 0));
+            }
+            // get animation info / verify there is such a range from the source bone
+            var sourceRange = source.animations[0].getRange(rangeName);
+            if (!sourceRange) {
+                return false;
+            }
+            var from = sourceRange.from;
+            var to = sourceRange.to;
+            var sourceKeys = source.animations[0].getKeys();
+            // rescaling prep
+            var sourceBoneLength = source.length;
+            var scalingReqd = rescaleAsRequired && sourceBoneLength && this.length && sourceBoneLength !== this.length;
+            var ratio = scalingReqd ? this.length / sourceBoneLength : null;
+            var destKeys = this.animations[0].getKeys();
+            // loop vars declaration / initialization
+            var orig;
+            var origScale = scalingReqd ? BABYLON.Vector3.Zero() : null;
+            var origRotation = scalingReqd ? new BABYLON.Quaternion() : null;
+            var origTranslation = scalingReqd ? BABYLON.Vector3.Zero() : null;
+            var mat;
+            for (var key = 0, nKeys = sourceKeys.length; key < nKeys; key++) {
+                orig = sourceKeys[key];
+                if (orig.frame >= from && orig.frame <= to) {
+                    if (scalingReqd) {
+                        orig.value.decompose(origScale, origRotation, origTranslation);
+                        origTranslation.scaleInPlace(ratio);
+                        mat = BABYLON.Matrix.Compose(origScale, origRotation, origTranslation);
+                    }
+                    else {
+                        mat = orig.value;
+                    }
+                    destKeys.push({ frame: orig.frame + frameOffset, value: mat });
+                }
+            }
+            this.animations[0].createRange(rangeName, from + frameOffset, to + frameOffset);
+            return true;
+        };
         return Bone;
     })(BABYLON.Node);
     BABYLON.Bone = Bone;

+ 17 - 15
src/Bones/babylon.bone.ts

@@ -2,7 +2,7 @@
     export class Bone extends Node {
         public children = new Array<Bone>();
         public animations = new Array<Animation>();
-        public length: number; 
+        public length: number;
 
         private _skeleton: Skeleton;
         private _matrix: Matrix;
@@ -31,11 +31,11 @@
         }
 
         // Members
-        public getParent():Bone {
+        public getParent(): Bone {
             return this._parent;
         }
 
-        public getLocalMatrix():Matrix {
+        public getLocalMatrix(): Matrix {
             return this._matrix;
         }
 
@@ -89,16 +89,18 @@
             this._currentRenderId++;
             this._skeleton._markAsDirty();
         }
-        
-        public copyAnimationRange(source : Bone, rangeName : string, frameOffset : number, rescaleAsRequired = false) : boolean{
+
+        public copyAnimationRange(source: Bone, rangeName: string, frameOffset: number, rescaleAsRequired = false): boolean {
             // all animation may be coming from a library skeleton, so may need to create animation
-            if (this.animations.length === 0){
-                this.animations.push(new Animation(this.name, "_matrix", source.animations[0].framePerSecond, Animation.ANIMATIONTYPE_MATRIX, 0) ); 
+            if (this.animations.length === 0) {
+                this.animations.push(new Animation(this.name, "_matrix", source.animations[0].framePerSecond, Animation.ANIMATIONTYPE_MATRIX, 0));
             }
 
             // get animation info / verify there is such a range from the source bone
             var sourceRange = source.animations[0].getRange(rangeName);
-            if (!sourceRange) return false;
+            if (!sourceRange) {
+                return false;
+            }
             var from = sourceRange.from;
             var to = sourceRange.to;
             var sourceKeys = source.animations[0].getKeys();
@@ -107,31 +109,31 @@
             var sourceBoneLength = source.length;
             var scalingReqd = rescaleAsRequired && sourceBoneLength && this.length && sourceBoneLength !== this.length;
             var ratio = scalingReqd ? this.length / sourceBoneLength : null;
-            
+
             var destKeys = this.animations[0].getKeys();
             
             // loop vars declaration / initialization
-            var orig : {frame : number, value : Matrix};
+            var orig: { frame: number, value: Matrix };
             var origScale = scalingReqd ? BABYLON.Vector3.Zero() : null;
             var origRotation = scalingReqd ? new BABYLON.Quaternion() : null;
             var origTranslation = scalingReqd ? BABYLON.Vector3.Zero() : null;
-            var mat : Matrix;
+            var mat: Matrix;
 
             for (var key = 0, nKeys = sourceKeys.length; key < nKeys; key++) {
                 orig = sourceKeys[key];
-                if (orig.frame >= from  && orig.frame <= to) {
+                if (orig.frame >= from && orig.frame <= to) {
                     if (scalingReqd) {
                         orig.value.decompose(origScale, origRotation, origTranslation);
                         origTranslation.scaleInPlace(ratio);
                         mat = Matrix.Compose(origScale, origRotation, origTranslation);
-                    }else {
+                    } else {
                         mat = orig.value;
                     }
-                    destKeys.push({frame: orig.frame + frameOffset, value: mat});
+                    destKeys.push({ frame: orig.frame + frameOffset, value: mat });
                 }
             }
             this.animations[0].createRange(rangeName, from + frameOffset, to + frameOffset);
             return true;
         }
     }
-} 
+} 

+ 74 - 11
src/Bones/babylon.skeleton.js

@@ -7,7 +7,7 @@ var BABYLON;
             this.bones = new Array();
             this._isDirty = true;
             this._identity = BABYLON.Matrix.Identity();
-            this._ranges = new Array();
+            this._ranges = {};
             this.bones = [];
             this._scene = scene;
             scene.skeletons.push(this);
@@ -24,23 +24,71 @@ var BABYLON;
         };
         // Methods
         Skeleton.prototype.createAnimationRange = function (name, from, to) {
-            this._ranges.push(new BABYLON.AnimationRange(name, from, to));
+            // check name not already in use
+            if (!this._ranges[name]) {
+                this._ranges[name] = new BABYLON.AnimationRange(name, from, to);
+                for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
+                    if (this.bones[i].animations[0]) {
+                        this.bones[i].animations[0].createRange(name, from, to);
+                    }
+                }
+            }
         };
-        Skeleton.prototype.deleteAnimationRange = function (name) {
-            for (var index = 0; index < this._ranges.length; index++) {
-                if (this._ranges[index].name === name) {
-                    this._ranges.splice(index, 1);
-                    return;
+        Skeleton.prototype.deleteAnimationRange = function (name, deleteFrames) {
+            if (deleteFrames === void 0) { deleteFrames = true; }
+            for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
+                if (this.bones[i].animations[0]) {
+                    this.bones[i].animations[0].deleteRange(name, deleteFrames);
                 }
             }
+            this._ranges[name] = undefined; // said much faster than 'delete this._range[name]' 
         };
         Skeleton.prototype.getAnimationRange = function (name) {
-            for (var index = 0; index < this._ranges.length; index++) {
-                if (this._ranges[index].name === name) {
-                    return this._ranges[index];
+            return this._ranges[name];
+        };
+        /**
+         *  note: This is not for a complete retargeting, only between very similar skeleton's with only possible bone length differences
+         */
+        Skeleton.prototype.copyAnimationRange = function (source, name, rescaleAsRequired) {
+            if (rescaleAsRequired === void 0) { rescaleAsRequired = false; }
+            if (this._ranges[name] || !source.getAnimationRange(name)) {
+                return false;
+            }
+            var ret = true;
+            var frameOffset = this._getHighestAnimationFrame() + 1;
+            // make a dictionary of source skeleton's bones, so exact same order or doublely nested loop is not required
+            var boneDict = {};
+            var sourceBones = source.bones;
+            for (var i = 0, nBones = sourceBones.length; i < nBones; i++) {
+                boneDict[sourceBones[i].name] = sourceBones[i];
+            }
+            for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
+                var boneName = this.bones[i].name;
+                var sourceBone = boneDict[boneName];
+                if (sourceBone) {
+                    ret = ret && this.bones[i].copyAnimationRange(sourceBone, name, frameOffset, rescaleAsRequired);
+                }
+                else {
+                    BABYLON.Tools.Warn("copyAnimationRange: not same rig, missing source bone " + boneName);
+                    ret = false;
                 }
             }
-            return null;
+            // do not call createAnimationRange(), since it also is done to bones, which was already done
+            var range = source.getAnimationRange(name);
+            this._ranges[name] = new BABYLON.AnimationRange(name, range.from + frameOffset, range.to + frameOffset);
+            return ret;
+        };
+        Skeleton.prototype._getHighestAnimationFrame = function () {
+            var ret = 0;
+            for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
+                if (this.bones[i].animations[0]) {
+                    var highest = this.bones[i].animations[0].getHighestFrame();
+                    if (ret < highest) {
+                        ret = highest;
+                    }
+                }
+            }
+            return ret;
         };
         Skeleton.prototype.beginAnimation = function (name, loop, speedRatio, onAnimationEnd) {
             var range = this.getAnimationRange(name);
@@ -122,6 +170,14 @@ var BABYLON;
                 if (bone.animations && bone.animations.length > 0) {
                     serializedBone.animation = bone.animations[0].serialize();
                 }
+                serializationObject.ranges = [];
+                for (var name in this._ranges) {
+                    var range = {};
+                    range.name = name;
+                    range.from = this._ranges[name].from;
+                    range.to = this._ranges[name].to;
+                    serializationObject.ranges.push(range);
+                }
             }
             return serializationObject;
         };
@@ -141,6 +197,13 @@ var BABYLON;
                     bone.animations.push(BABYLON.Animation.Parse(parsedBone.animation));
                 }
             }
+            // placed after bones, so createAnimationRange can cascade down
+            if (parsedSkeleton.ranges) {
+                for (var index = 0; index < parsedSkeleton.ranges.length; index++) {
+                    var data = parsedSkeleton.ranges[index];
+                    skeleton.createAnimationRange(data.name, data.from, data.to);
+                }
+            }
             return skeleton;
         };
         return Skeleton;

+ 20 - 19
src/Bones/babylon.skeleton.ts

@@ -8,7 +8,7 @@
         private _animatables: IAnimatable[];
         private _identity = Matrix.Identity();
 
-        private _ranges : { [name: string] : AnimationRange; } = {};
+        private _ranges: { [name: string]: AnimationRange; } = {};
 
         constructor(public name: string, public id: string, scene: Scene) {
             this.bones = [];
@@ -34,7 +34,7 @@
         // Methods
         public createAnimationRange(name: string, from: number, to: number): void {
             // check name not already in use
-            if (! this._ranges[name]){
+            if (!this._ranges[name]) {
                 this._ranges[name] = new AnimationRange(name, from, to);
                 for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
                     if (this.bones[i].animations[0]) {
@@ -60,9 +60,9 @@
         /** 
          *  note: This is not for a complete retargeting, only between very similar skeleton's with only possible bone length differences
          */
-        public copyAnimationRange(source : Skeleton, name : string, rescaleAsRequired = false) : boolean {
-            if (this._ranges[name] || !source.getAnimationRange(name) ){
-               return false; 
+        public copyAnimationRange(source: Skeleton, name: string, rescaleAsRequired = false): boolean {
+            if (this._ranges[name] || !source.getAnimationRange(name)) {
+                return false;
             }
             var ret = true;
             var frameOffset = this._getHighestAnimationFrame() + 1;
@@ -77,9 +77,9 @@
             for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
                 var boneName = this.bones[i].name;
                 var sourceBone = boneDict[boneName];
-                if (sourceBone){
+                if (sourceBone) {
                     ret = ret && this.bones[i].copyAnimationRange(sourceBone, name, frameOffset, rescaleAsRequired);
-                }else{
+                } else {
                     BABYLON.Tools.Warn("copyAnimationRange: not same rig, missing source bone " + boneName);
                     ret = false;
                 }
@@ -89,14 +89,14 @@
             this._ranges[name] = new AnimationRange(name, range.from + frameOffset, range.to + frameOffset);
             return ret;
         }
-        
-        private _getHighestAnimationFrame() : number {
-            var ret = 0; 
+
+        private _getHighestAnimationFrame(): number {
+            var ret = 0;
             for (var i = 0, nBones = this.bones.length; i < nBones; i++) {
                 if (this.bones[i].animations[0]) {
                     var highest = this.bones[i].animations[0].getHighestFrame();
                     if (ret < highest) {
-                        ret = highest; 
+                        ret = highest;
                     }
                 }
             }
@@ -157,7 +157,7 @@
 
             return this._animatables;
         }
-        
+
         public clone(name: string, id: string): Skeleton {
             var result = new Skeleton(name, id || name, this._scene);
 
@@ -211,13 +211,13 @@
                 if (bone.animations && bone.animations.length > 0) {
                     serializedBone.animation = bone.animations[0].serialize();
                 }
-                
+
                 serializationObject.ranges = [];
                 for (var name in this._ranges) {
                     var range: any = {};
                     range.name = name;
                     range.from = this._ranges[name].from;
-                    range.to   = this._ranges[name].to;
+                    range.to = this._ranges[name].to;
                     serializationObject.ranges.push(range);
                 }
             }
@@ -247,13 +247,14 @@
             }
             
             // placed after bones, so createAnimationRange can cascade down
-            if (parsedSkeleton.ranges){
-               for (var index = 0; index < parsedSkeleton.ranges.length; index++) {
-                   var data = parsedSkeleton.ranges[index];
-                   skeleton.createAnimationRange(data.name, data.from, data.to);
-               }
+            if (parsedSkeleton.ranges) {
+                for (var index = 0; index < parsedSkeleton.ranges.length; index++) {
+                    var data = parsedSkeleton.ranges[index];
+                    skeleton.createAnimationRange(data.name, data.from, data.to);
+                }
             }
             return skeleton;
         }
     }
 }
+

+ 2 - 0
src/Cameras/babylon.camera.js

@@ -533,6 +533,7 @@ var BABYLON;
             serializationObject.inertia = this.inertia;
             // Animations
             BABYLON.Animation.AppendSerializedAnimations(this, serializationObject);
+            serializationObject.ranges = this.serializeAnimationRanges();
             // Layer mask
             serializationObject.layerMask = this.layerMask;
             return serializationObject;
@@ -632,6 +633,7 @@ var BABYLON;
                     var parsedAnimation = parsedCamera.animations[animationIndex];
                     camera.animations.push(BABYLON.Animation.Parse(parsedAnimation));
                 }
+                BABYLON.Node.ParseAnimationRanges(camera, parsedCamera, scene);
             }
             if (parsedCamera.autoAnimate) {
                 scene.beginAnimation(camera, parsedCamera.autoAnimateFrom, parsedCamera.autoAnimateTo, parsedCamera.autoAnimateLoop, 1.0);

+ 8 - 7
src/Cameras/babylon.camera.ts

@@ -53,7 +53,7 @@
             result.hScreenSize = 0.149759993;
             result.vScreenSize = 0.0935999975;
             result.vScreenCenter = 0.0467999987,
-            result.eyeToScreenDistance = 0.0410000011;
+                result.eyeToScreenDistance = 0.0410000011;
             result.lensSeparationDistance = 0.0635000020;
             result.interpupillaryDistance = 0.0640000030;
             result.distortionK = [1.0, 0.219999999, 0.239999995, 0.0];
@@ -253,15 +253,15 @@
 
             if (this.mode === Camera.PERSPECTIVE_CAMERA) {
                 check = this._cache.fov === this.fov
-                && this._cache.aspectRatio === engine.getAspectRatio(this);
+                    && this._cache.aspectRatio === engine.getAspectRatio(this);
             }
             else {
                 check = this._cache.orthoLeft === this.orthoLeft
-                && this._cache.orthoRight === this.orthoRight
-                && this._cache.orthoBottom === this.orthoBottom
-                && this._cache.orthoTop === this.orthoTop
-                && this._cache.renderWidth === engine.getRenderWidth()
-                && this._cache.renderHeight === engine.getRenderHeight();
+                    && this._cache.orthoRight === this.orthoRight
+                    && this._cache.orthoBottom === this.orthoBottom
+                    && this._cache.orthoTop === this.orthoTop
+                    && this._cache.renderWidth === engine.getRenderWidth()
+                    && this._cache.renderHeight === engine.getRenderHeight();
             }
 
             return check;
@@ -738,3 +738,4 @@
     }
 }
 
+

+ 1 - 0
src/Lights/babylon.light.js

@@ -130,6 +130,7 @@ var BABYLON;
                     var parsedAnimation = parsedLight.animations[animationIndex];
                     light.animations.push(BABYLON.Animation.Parse(parsedAnimation));
                 }
+                BABYLON.Node.ParseAnimationRanges(light, parsedLight, scene);
             }
             if (parsedLight.autoAnimate) {
                 scene.beginAnimation(light, parsedLight.autoAnimateFrom, parsedLight.autoAnimateTo, parsedLight.autoAnimateLoop, 1.0);

+ 2 - 1
src/Lights/babylon.light.ts

@@ -192,8 +192,9 @@
             if (parsedLight.autoAnimate) {
                 scene.beginAnimation(light, parsedLight.autoAnimateFrom, parsedLight.autoAnimateTo, parsedLight.autoAnimateLoop, 1.0);
             }
-            
+
             return light;
         }
     }
 } 
+

+ 10 - 16
src/Math/babylon.math.js

@@ -847,7 +847,7 @@ var BABYLON;
             return center;
         };
         /**
-         * Given three orthogonal left-handed oriented Vector3 axis in space (target system),
+         * Given three orthogonal normalized left-handed oriented Vector3 axis in space (target system),
          * RotationFromAxis() returns the rotation Euler angles (ex : rotation.x, rotation.y, rotation.z) to apply
          * to something in order to rotate it from its local system to the given target system.
          */
@@ -860,8 +860,8 @@ var BABYLON;
          * The same than RotationFromAxis but updates the passed ref Vector3 parameter.
          */
         Vector3.RotationFromAxisToRef = function (axis1, axis2, axis3, ref) {
-            var u = Vector3.Normalize(axis1);
-            var w = Vector3.Normalize(axis3);
+            var u = axis1.normalize();
+            var w = axis3.normalize();
             // world axis
             var X = Axis.X;
             var Y = Axis.Y;
@@ -875,13 +875,12 @@ var BABYLON;
             var t = 0.0;
             var sign = -1.0;
             var nbRevert = 0;
-            var cross;
+            var cross = Vector3.Zero();
             var dot = 0.0;
             // step 1  : rotation around w
             // Rv3(u) = u1, and u1 belongs to plane xOz
             // Rv3(w) = w1 = w invariant
             var u1;
-            var v1;
             if (BABYLON.Tools.WithinEpsilon(w.z, 0, BABYLON.Engine.Epsilon)) {
                 z = 1.0;
             }
@@ -895,9 +894,7 @@ var BABYLON;
             }
             u1 = new Vector3(x, y, z);
             u1.normalize();
-            v1 = Vector3.Cross(w, u1); // v1 image of v through rotation around w
-            v1.normalize();
-            cross = Vector3.Cross(u, u1); // returns same direction as w (=local z) if positive angle : cross(source, image)
+            Vector3.CrossToRef(u, u1, cross); // returns same direction as w (=local z) if positive angle : cross(source, image)
             cross.normalize();
             if (Vector3.Dot(w, cross) < 0) {
                 sign = 1.0;
@@ -908,7 +905,6 @@ var BABYLON;
             if (Vector3.Dot(u1, X) < 0) {
                 roll = Math.PI + roll;
                 u1 = u1.scaleInPlace(-1);
-                v1 = v1.scaleInPlace(-1);
                 nbRevert++;
             }
             // step 2 : rotate around u1
@@ -919,7 +915,7 @@ var BABYLON;
             x = 0.0;
             y = 0.0;
             z = 0.0;
-            sign = -1;
+            sign = -1.0;
             if (BABYLON.Tools.WithinEpsilon(w.z, 0, BABYLON.Engine.Epsilon)) {
                 x = 1.0;
             }
@@ -932,7 +928,7 @@ var BABYLON;
             w2.normalize();
             v2 = Vector3.Cross(w2, u1); // v2 image of v1 through rotation around u1
             v2.normalize();
-            cross = Vector3.Cross(w, w2); // returns same direction as u1 (=local x) if positive angle : cross(source, image)
+            Vector3.CrossToRef(w, w2, cross); // returns same direction as u1 (=local x) if positive angle : cross(source, image)
             cross.normalize();
             if (Vector3.Dot(u1, cross) < 0) {
                 sign = 1.0;
@@ -942,14 +938,12 @@ var BABYLON;
             pitch = Math.acos(dot) * sign;
             if (Vector3.Dot(v2, Y) < 0) {
                 pitch = Math.PI + pitch;
-                v2 = v2.scaleInPlace(-1);
-                w2 = w2.scaleInPlace(-1);
                 nbRevert++;
             }
             // step 3 : rotate around v2
             // Rv2(u1) = X, same as Rv2(w2) = Z, with X=(1,0,0) and Z=(0,0,1)
-            sign = -1;
-            cross = Vector3.Cross(X, u1); // returns same direction as Y if positive angle : cross(source, image)
+            sign = -1.0;
+            Vector3.CrossToRef(X, u1, cross); // returns same direction as Y if positive angle : cross(source, image)
             cross.normalize();
             if (Vector3.Dot(cross, Y) < 0) {
                 sign = 1.0;
@@ -1963,7 +1957,7 @@ var BABYLON;
             // Z axis
             target.subtractToRef(eye, this._zAxis);
             this._zAxis.normalize();
-            // X axis            
+            // X axis
             Vector3.CrossToRef(up, this._zAxis, this._xAxis);
             if (this._xAxis.lengthSquared() === 0) {
                 this._xAxis.x = 1.0;

+ 1 - 0
src/Math/babylon.math.ts

@@ -3613,3 +3613,4 @@
         }
     }
 }
+

+ 38 - 3
src/Mesh/babylon.groundMesh.js

@@ -25,23 +25,52 @@ var BABYLON;
             this.subdivide(this._subdivisions);
             this.createOrUpdateSubmeshesOctree(octreeBlocksSize);
         };
+        /**
+         * Returns a height (y) value in the Worl system :
+         * the ground altitude at the coordinates (x, z) expressed in the World system.
+         * Returns the ground y position if (x, z) are outside the ground surface.
+         * Not pertinent if the ground is rotated.
+         */
         GroundMesh.prototype.getHeightAtCoordinates = function (x, z) {
+            // express x and y in the ground local system
+            x -= this.position.x;
+            z -= this.position.z;
+            x /= this.scaling.x;
+            z /= this.scaling.z;
             if (x < this._minX || x > this._maxX || z < this._minZ || z > this._maxZ) {
-                return 0;
+                return this.position.y;
             }
             if (!this._heightQuads || this._heightQuads.length == 0) {
                 this._computeHeightQuads();
             }
             var facet = this._getFacetAt(x, z);
             var y = -(facet.x * x + facet.z * z + facet.w) / facet.y;
-            return y;
+            // return y in the World system
+            return y * this.scaling.y + this.position.y;
         };
+        /**
+         * Returns a normalized vector (Vector3) orthogonal to the ground
+         * at the ground coordinates (x, z) expressed in the World system.
+         * Returns Vector3(0, 1, 0) if (x, z) are outside the ground surface.
+         * Not pertinent if the ground is rotated.
+         */
         GroundMesh.prototype.getNormalAtCoordinates = function (x, z) {
             var normal = new BABYLON.Vector3(0, 1, 0);
             this.getNormalAtCoordinatesToRef(x, z, normal);
             return normal;
         };
+        /**
+         * Updates the Vector3 passed a reference with a normalized vector orthogonal to the ground
+         * at the ground coordinates (x, z) expressed in the World system.
+         * Doesn't uptade the reference Vector3 if (x, z) are outside the ground surface.
+         * Not pertinent if the ground is rotated.
+         */
         GroundMesh.prototype.getNormalAtCoordinatesToRef = function (x, z, ref) {
+            // express x and y in the ground local system
+            x -= this.position.x;
+            z -= this.position.z;
+            x /= this.scaling.x;
+            z /= this.scaling.z;
             if (x < this._minX || x > this._maxX || z < this._minZ || z > this._maxZ) {
                 return;
             }
@@ -53,8 +82,9 @@ var BABYLON;
             ref.y = facet.y;
             ref.z = facet.z;
         };
+        // Returns the element "facet" from the heightQuads array relative to (x, z) local coordinates
         GroundMesh.prototype._getFacetAt = function (x, z) {
-            // retrieve col and row from x, z coordinates
+            // retrieve col and row from x, z coordinates in the ground local system
             var col = Math.floor((x + this._maxX) * this._subdivisions / this._width);
             var row = Math.floor(-(z + this._maxZ) * this._subdivisions / this._height + this._subdivisions);
             var quad = this._heightQuads[row * this._subdivisions + col];
@@ -67,6 +97,11 @@ var BABYLON;
             }
             return facet;
         };
+        // Populates the heightMap array with "facet" elements :
+        // a quad is two triangular facets separated by a slope, so a "facet" element is 1 slope + 2 facets
+        // slope : Vector2(c, h) = 2D diagonal line equation setting appart two triangular facets in a quad : z = cx + h
+        // facet1 : Vector4(a, b, c, d) = first facet 3D plane equation : ax + by + cz + d = 0
+        // facet2 :  Vector4(a, b, c, d) = second facet 3D plane equation : ax + by + cz + d = 0
         GroundMesh.prototype._computeHeightQuads = function () {
             this._heightQuads = new Array();
             var positions = this.getVerticesData(BABYLON.VertexBuffer.PositionKind);

+ 1 - 0
src/Mesh/babylon.groundMesh.ts

@@ -173,3 +173,4 @@
         }
     }
 }
+

+ 2 - 0
src/Mesh/babylon.mesh.js

@@ -1251,6 +1251,7 @@ var BABYLON;
                     var parsedAnimation = parsedMesh.animations[animationIndex];
                     mesh.animations.push(BABYLON.Animation.Parse(parsedAnimation));
                 }
+                BABYLON.Node.ParseAnimationRanges(mesh, parsedMesh, scene);
             }
             if (parsedMesh.autoAnimate) {
                 scene.beginAnimation(mesh, parsedMesh.autoAnimateFrom, parsedMesh.autoAnimateTo, parsedMesh.autoAnimateLoop, 1.0);
@@ -1282,6 +1283,7 @@ var BABYLON;
                             parsedAnimation = parsedMesh.animations[animationIndex];
                             instance.animations.push(BABYLON.Animation.Parse(parsedAnimation));
                         }
+                        BABYLON.Node.ParseAnimationRanges(instance, parsedMesh, scene);
                     }
                 }
             }

+ 1 - 0
src/Mesh/babylon.mesh.ts

@@ -2011,3 +2011,4 @@
 
 
 
+

+ 1 - 1
src/Mesh/babylon.meshBuilder.js

@@ -252,7 +252,7 @@ var BABYLON;
                 var path = [];
                 if (cap == BABYLON.Mesh.CAP_START || cap == BABYLON.Mesh.CAP_ALL) {
                     path.push(new BABYLON.Vector3(0, shape[0].y, 0));
-                    path.push(new BABYLON.Vector3(shape[0].x, shape[0].y, shape[0].x));
+                    path.push(new BABYLON.Vector3(Math.cos(i * step) * shape[0].x * radius, shape[0].y, Math.sin(i * step) * shape[0].x * radius));
                 }
                 for (p = 0; p < shape.length; p++) {
                     rotated = new BABYLON.Vector3(Math.cos(i * step) * shape[p].x * radius, shape[p].y, Math.sin(i * step) * shape[p].x * radius);

+ 1 - 0
src/Mesh/babylon.meshBuilder.ts

@@ -812,3 +812,4 @@
         }
     }
 }
+

+ 107 - 21
src/Particles/babylon.solidParticleSystem.js

@@ -1,8 +1,17 @@
 var BABYLON;
 (function (BABYLON) {
+    /**
+    * Full documentation here : http://doc.babylonjs.com/tutorials/Solid_Particle_System
+    */
     var SolidParticleSystem = (function () {
+        /**
+        * Creates a SPS (Solid Particle System) object.
+        * @param name the SPS name, this will be the underlying mesh name
+        * @param updatable (default true) if the SPS must be updatable or immutable
+        * @param isPickable (default false) if the solid particles must be pickable
+        */
         function SolidParticleSystem(name, scene, options) {
-            // public members  
+            // public members
             this.particles = new Array();
             this.nbParticles = 0;
             this.billboard = false;
@@ -64,7 +73,10 @@ var BABYLON;
                 this.pickedParticles = [];
             }
         }
-        // build the SPS mesh : returns the mesh
+        /**
+        * Builds the SPS underlying mesh. Returns a standard Mesh.
+        * If no model shape was added to the SPS, the return mesh is only a single triangular plane.
+        */
         SolidParticleSystem.prototype.buildMesh = function () {
             if (this.nbParticles === 0) {
                 var triangle = BABYLON.MeshBuilder.CreateDisc("", { radius: 1, tessellation: 3 }, this._scene);
@@ -207,7 +219,14 @@ var BABYLON;
         SolidParticleSystem.prototype._addParticle = function (idx, idxpos, model, shapeId, idxInShape) {
             this.particles.push(new BABYLON.SolidParticle(idx, idxpos, model, shapeId, idxInShape));
         };
-        // add solid particles from a shape model in the particles array
+        /**
+        * Adds some particles to the SPS from the model shape.
+        * Please read the doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#create-an-immutable-sps
+        * @param mesh any Mesh object that will be used as a model for the solid particles.
+        * @param nb the number of particles to be created from this model
+        * @param positionFunction an optional javascript function to called for each particle on SPS creation
+        * @param vertexFunction an optional javascript function to called for each vertex of each particle on SPS creation
+        */
         SolidParticleSystem.prototype.addShape = function (mesh, nb, options) {
             var meshPos = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
             var meshInd = mesh.getIndices();
@@ -278,14 +297,23 @@ var BABYLON;
             particle.scale.y = 1;
             particle.scale.z = 1;
         };
-        // rebuilds the whole mesh and updates the VBO : custom positions and vertices are recomputed if needed
+        /**
+        * Rebuilds the whole mesh and updates the VBO : custom positions and vertices are recomputed if needed.
+        */
         SolidParticleSystem.prototype.rebuildMesh = function () {
             for (var p = 0; p < this.particles.length; p++) {
                 this._rebuildParticle(this.particles[p]);
             }
             this.mesh.updateVerticesData(BABYLON.VertexBuffer.PositionKind, this._positions32, false, false);
         };
-        // sets all the particles : updates the VBO
+        /**
+        *  Sets all the particles : this method actually really updates the mesh according to the particle positions, rotations, colors, textures, etc.
+        *  This method calls updateParticle() for each particles of the SPS.
+        *  For an animated SPS, it is usually called within the render loop.
+        * @param start (default 0) the particle index in the particle array where to start to compute the particle property values
+        * @param end (default nbParticle - 1)  the particle index in the particle array where to stop to compute the particle property values
+        * @param update (default true) if the mesh must be finally updated on this call after all the particle computations.
+        */
         SolidParticleSystem.prototype.setParticles = function (start, end, update) {
             if (start === void 0) { start = 0; }
             if (end === void 0) { end = this.nbParticles - 1; }
@@ -460,7 +488,9 @@ var BABYLON;
             this._rotMatrix.m[14] = 0;
             this._rotMatrix.m[15] = 1.0;
         };
-        // dispose the SPS
+        /**
+        * Disposes the SPS
+        */
         SolidParticleSystem.prototype.dispose = function () {
             this.mesh.dispose();
             this.vars = null;
@@ -477,15 +507,25 @@ var BABYLON;
             this._colors32 = null;
             this.pickedParticles = null;
         };
-        // Visibilty helpers
+        /**
+        *  Visibilty helper : Recomputes the visible size according to the mesh bounding box
+        * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#sps-visibility
+        */
         SolidParticleSystem.prototype.refreshVisibleSize = function () {
             this.mesh.refreshBoundingInfo();
         };
         Object.defineProperty(SolidParticleSystem.prototype, "isAlwaysVisible", {
             // getter and setter
+            /**
+            * True if the SPS is set as always visible
+            */
             get: function () {
                 return this._alwaysVisible;
             },
+            /**
+            * Sets the SPS as always visible or not
+            * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#sps-visibility
+            */
             set: function (val) {
                 this._alwaysVisible = val;
                 this.mesh.alwaysSelectAsActiveMesh = val;
@@ -499,6 +539,11 @@ var BABYLON;
                 return this._computeParticleRotation;
             },
             // Optimizer setters
+            /**
+            * Tells to setParticle() to compute the particle rotations or not.
+            * Default value : true. The SPS is faster when it's set to false.
+            * Note : the particle rotations aren't stored values, so setting computeParticleRotation to false will prevents the particle to rotate.
+            */
             set: function (val) {
                 this._computeParticleRotation = val;
             },
@@ -509,6 +554,11 @@ var BABYLON;
             get: function () {
                 return this._computeParticleColor;
             },
+            /**
+            * Tells to setParticle() to compute the particle colors or not.
+            * Default value : true. The SPS is faster when it's set to false.
+            * Note : the particle colors are stored values, so setting computeParticleColor to false will keep yet the last colors set.
+            */
             set: function (val) {
                 this._computeParticleColor = val;
             },
@@ -519,6 +569,11 @@ var BABYLON;
             get: function () {
                 return this._computeParticleTexture;
             },
+            /**
+            * Tells to setParticle() to compute the particle textures or not.
+            * Default value : true. The SPS is faster when it's set to false.
+            * Note : the particle textures are stored values, so setting computeParticleTexture to false will keep yet the last colors set.
+            */
             set: function (val) {
                 this._computeParticleTexture = val;
             },
@@ -529,6 +584,11 @@ var BABYLON;
             get: function () {
                 return this._computeParticleVertex;
             },
+            /**
+            * Tells to setParticle() to call the vertex function for each vertex of each particle, or not.
+            * Default value : false. The SPS is faster when it's set to false.
+            * Note : the particle custom vertex positions aren't stored values.
+            */
             set: function (val) {
                 this._computeParticleVertex = val;
             },
@@ -538,33 +598,59 @@ var BABYLON;
         // =======================================================================
         // Particle behavior logic
         // these following methods may be overwritten by the user to fit his needs
-        // init : sets all particles first values and calls updateParticle to set them in space
-        // can be overwritten by the user
+        /**
+        * This function does nothing. It may be overwritten to set all the particles first values.
+        * The SPS doesn't call this function, you may have to call it by your own.
+        * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#particle-management
+        */
         SolidParticleSystem.prototype.initParticles = function () {
         };
-        // recycles a particle : can by overwritten by the user
+        /**
+        * This function does nothing. It may be overwritten to recycle a particle.
+        * The SPS doesn't call this function, you may have to call it by your own.
+        * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#particle-management
+        */
         SolidParticleSystem.prototype.recycleParticle = function (particle) {
             return particle;
         };
-        // updates a particle : can be overwritten by the user
-        // will be called on each particle by setParticles() :
-        // ex : just set a particle position or velocity and recycle conditions
+        /**
+        * Updates a particle : this function should  be overwritten by the user.
+        * It is called on each particle by setParticles(). This is the place to code each particle behavior.
+        * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#particle-management
+        * ex : just set a particle position or velocity and recycle conditions
+        */
         SolidParticleSystem.prototype.updateParticle = function (particle) {
             return particle;
         };
-        // updates a vertex of a particle : can be overwritten by the user
-        // will be called on each vertex particle by setParticles() :
-        // particle : the current particle
-        // vertex : the current index of the current particle
-        // pt : the index of the current vertex in the particle shape
-        // ex : just set a vertex particle position
+        /**
+        * Updates a vertex of a particle : it can be overwritten by the user.
+        * This will be called on each vertex particle by setParticles() if computeParticleVertex is set to true only.
+        * @param particle the current particle
+        * @param vertex the current index of the current particle
+        * @param pt the index of the current vertex in the particle shape
+        * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#update-each-particle-shape
+        * ex : just set a vertex particle position
+        */
         SolidParticleSystem.prototype.updateParticleVertex = function (particle, vertex, pt) {
             return vertex;
         };
-        // will be called before any other treatment by setParticles()
+        /**
+        * This will be called before any other treatment by setParticles() and will be passed three parameters.
+        * This does nothing and may be overwritten by the user.
+        * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+        * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+        * @param update the boolean update value actually passed to setParticles()
+        */
         SolidParticleSystem.prototype.beforeUpdateParticles = function (start, stop, update) {
         };
-        // will be called after all setParticles() treatments
+        /**
+        * This will be called  by setParticles() after all the other treatments and just before the actual mesh update.
+        * This will be passed three parameters.
+        * This does nothing and may be overwritten by the user.
+        * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+        * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
+        * @param update the boolean update value actually passed to setParticles()
+        */
         SolidParticleSystem.prototype.afterUpdateParticles = function (start, stop, update) {
         };
         return SolidParticleSystem;

+ 1 - 0
src/Particles/babylon.solidParticleSystem.ts

@@ -716,3 +716,4 @@ module BABYLON {
         }
     }
 }
+

+ 2 - 0
src/Tools/babylon.sceneSerializer.js

@@ -127,9 +127,11 @@ var BABYLON;
             serializationObject.instances.push(serializationInstance);
             // Animations
             BABYLON.Animation.AppendSerializedAnimations(instance, serializationInstance);
+            serializationInstance.ranges = instance.serializeAnimationRanges();
         }
         // Animations
         BABYLON.Animation.AppendSerializedAnimations(mesh, serializationObject);
+        serializationObject.ranges = mesh.serializeAnimationRanges();
         // Layer mask
         serializationObject.layerMask = mesh.layerMask;
         return serializationObject;

+ 1 - 1
src/Tools/babylon.sceneSerializer.ts

@@ -366,4 +366,4 @@
             return serializationObject;
         }
     }
-}
+}

+ 50 - 0
src/babylon.node.js

@@ -12,6 +12,7 @@ var BABYLON;
         function Node(name, scene) {
             this.state = "";
             this.animations = new Array();
+            this._ranges = {};
             this._childrenFlag = -1;
             this._isEnabled = true;
             this._isReady = true;
@@ -165,6 +166,55 @@ var BABYLON;
             }
             return null;
         };
+        Node.prototype.createAnimationRange = function (name, from, to) {
+            // check name not already in use
+            if (!this._ranges[name]) {
+                this._ranges[name] = new BABYLON.AnimationRange(name, from, to);
+                for (var i = 0, nAnimations = this.animations.length; i < nAnimations; i++) {
+                    if (this.animations[i]) {
+                        this.animations[i].createRange(name, from, to);
+                    }
+                }
+            }
+        };
+        Node.prototype.deleteAnimationRange = function (name, deleteFrames) {
+            if (deleteFrames === void 0) { deleteFrames = true; }
+            for (var i = 0, nAnimations = this.animations.length; i < nAnimations; i++) {
+                if (this.animations[i]) {
+                    this.animations[i].deleteRange(name, deleteFrames);
+                }
+            }
+            this._ranges[name] = undefined; // said much faster than 'delete this._range[name]' 
+        };
+        Node.prototype.getAnimationRange = function (name) {
+            return this._ranges[name];
+        };
+        Node.prototype.beginAnimation = function (name, loop, speedRatio, onAnimationEnd) {
+            var range = this.getAnimationRange(name);
+            if (!range) {
+                return null;
+            }
+            this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
+        };
+        Node.prototype.serializeAnimationRanges = function () {
+            var serializationRanges = [];
+            for (var name in this._ranges) {
+                var range = {};
+                range.name = name;
+                range.from = this._ranges[name].from;
+                range.to = this._ranges[name].to;
+                serializationRanges.push(range);
+            }
+            return serializationRanges;
+        };
+        Node.ParseAnimationRanges = function (node, parsedNode, scene) {
+            if (parsedNode.ranges) {
+                for (var index = 0; index < parsedNode.ranges.length; index++) {
+                    var data = parsedNode.ranges[index];
+                    node.createAnimationRange(data.name, data.from, data.to);
+                }
+            }
+        };
         return Node;
     })();
     BABYLON.Node = Node;

+ 14 - 14
src/babylon.node.ts

@@ -11,7 +11,7 @@
         public state = "";
 
         public animations = new Array<Animation>();
-        private _ranges : { [name: string] : AnimationRange; } = {};
+        private _ranges: { [name: string]: AnimationRange; } = {};
 
         public onReady: (node: Node) => void;
 
@@ -80,7 +80,7 @@
         public _markSyncedWithParent() {
             this._parentRenderId = this.parent._currentRenderId;
         }
-        
+
         public isSynchronizedWithParent(): boolean {
             if (!this.parent) {
                 return true;
@@ -218,10 +218,10 @@
 
             return null;
         }
-        
+
         public createAnimationRange(name: string, from: number, to: number): void {
             // check name not already in use
-            if (! this._ranges[name]){
+            if (!this._ranges[name]) {
                 this._ranges[name] = new AnimationRange(name, from, to);
                 for (var i = 0, nAnimations = this.animations.length; i < nAnimations; i++) {
                     if (this.animations[i]) {
@@ -253,26 +253,26 @@
 
             this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
         }
-        
+
         public serializeAnimationRanges(): any {
             var serializationRanges = [];
             for (var name in this._ranges) {
                 var range: any = {};
                 range.name = name;
                 range.from = this._ranges[name].from;
-                range.to   = this._ranges[name].to;
+                range.to = this._ranges[name].to;
                 serializationRanges.push(range);
             }
             return serializationRanges;
         }
-        
-        public static ParseAnimationRanges(node : Node, parsedNode: any, scene: Scene): void {
-            if (parsedNode.ranges){
-               for (var index = 0; index < parsedNode.ranges.length; index++) {
-                   var data = parsedNode.ranges[index];
-                   node.createAnimationRange(data.name, data.from, data.to);
-               }
+
+        public static ParseAnimationRanges(node: Node, parsedNode: any, scene: Scene): void {
+            if (parsedNode.ranges) {
+                for (var index = 0; index < parsedNode.ranges.length; index++) {
+                    var data = parsedNode.ranges[index];
+                    node.createAnimationRange(data.name, data.from, data.to);
+                }
             }
         }
     }
-} 
+} 

+ 3 - 0
src/babylon.scene.js

@@ -1506,6 +1506,9 @@ var BABYLON;
                 var currentRenderId = this._renderId;
                 for (var cameraIndex = 0; cameraIndex < this.activeCameras.length; cameraIndex++) {
                     this._renderId = currentRenderId;
+                    if (cameraIndex > 0) {
+                        this._engine.clear(0, false, true);
+                    }
                     this._processSubCameras(this.activeCameras[cameraIndex]);
                 }
             }

+ 4 - 0
src/babylon.scene.ts

@@ -1905,6 +1905,10 @@
                 var currentRenderId = this._renderId;
                 for (var cameraIndex = 0; cameraIndex < this.activeCameras.length; cameraIndex++) {
                     this._renderId = currentRenderId;
+                    if (cameraIndex > 0) {
+                        this._engine.clear(0, false, true);
+                    }
+
                     this._processSubCameras(this.activeCameras[cameraIndex]);
                 }
             } else {