Przeglądaj źródła

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

# Conflicts:
#	dist/preview release/babylon.d.ts
#	dist/preview release/babylon.js
#	dist/preview release/babylon.max.js
#	dist/preview release/babylon.module.d.ts
#	dist/preview release/babylon.worker.js
#	dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
#	dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
#	dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
#	dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
#	dist/preview release/gui/babylon.gui.js
#	dist/preview release/gui/babylon.gui.min.js
David Rousset 7 lat temu
rodzic
commit
88c827b84c
33 zmienionych plików z 31213 dodań i 28978 usunięć
  1. 1 0
      Tools/Gulp/config.json
  2. 4 1
      Viewer/dist/basicExample.html
  3. 67 0
      Viewer/dist/eventsExample.html
  4. 3452 1657
      Viewer/dist/viewer.js
  5. 8 8
      Viewer/package.json
  6. 12 3
      Viewer/src/configuration/configuration.ts
  7. 2 2
      Viewer/src/configuration/types/default.ts
  8. 39 0
      Viewer/src/util/promiseObservable.ts
  9. 7 1
      Viewer/src/viewer/defaultViewer.ts
  10. 36 11
      Viewer/src/viewer/viewer.ts
  11. 23 0
      Viewer/src/viewer/viewerManager.ts
  12. 2227 2197
      dist/preview release/babylon.d.ts
  13. 41 41
      dist/preview release/babylon.js
  14. 1001 965
      dist/preview release/babylon.max.js
  15. 2227 2197
      dist/preview release/babylon.module.d.ts
  16. 41 41
      dist/preview release/babylon.worker.js
  17. 10145 10115
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  18. 38 38
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  19. 1008 979
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  20. 10145 10115
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
  21. 6 0
      dist/preview release/gui/babylon.gui.js
  22. 1 1
      dist/preview release/gui/babylon.gui.min.js
  23. 1 1
      dist/preview release/loaders/babylon.objFileLoader.min.js
  24. 2 2
      dist/preview release/loaders/babylonjs.loaders.min.js
  25. 1 0
      dist/preview release/what's new.md
  26. 6 0
      gui/src/advancedDynamicTexture.ts
  27. 32 30
      src/Engine/babylon.engine.ts
  28. 10 0
      src/Engine/babylon.nullEngine.ts
  29. 19 566
      src/Mesh/babylon.abstractMesh.ts
  30. 1 0
      src/Mesh/babylon.mesh.ts
  31. 602 0
      src/Mesh/babylon.transformNode.ts
  32. 3 3
      src/Physics/babylon.physicsImpostor.ts
  33. 5 4
      tests/nullEngine/app.js

+ 1 - 0
Tools/Gulp/config.json

@@ -181,6 +181,7 @@
                 "../../src/Culling/babylon.boundingSphere.js",
                 "../../src/Culling/babylon.boundingBox.js",
                 "../../src/Culling/babylon.boundingInfo.js",
+                "../../src/Mesh/babylon.transformNode.js",
                 "../../src/Mesh/babylon.abstractMesh.js",
                 "../../src/Lights/babylon.light.js",
                 "../../src/Cameras/babylon.camera.js",

+ 4 - 1
Viewer/dist/basicExample.html

@@ -11,7 +11,7 @@
                 max-width: 800px;
                 max-height: 500px;
                 width: 100%;
-                height: 100%;
+                height: 600px;
             }
         </style>
     </head>
@@ -21,6 +21,9 @@
             model.url="https://playground.babylonjs.com/scenes/Rabbit.babylon" camera.behaviors.auto-rotate="0" templates.nav-bar.params.disable-on-fullscreen="true"></babylon>
         <script src="viewer.js"></script>
         <script>
+            // The following lines are redundant. 
+            // They are only here to show how you could achive the tag initialization on your own.
+
             // a simple way of disabling auto init 
             BabylonViewer.disableInit = true;
             // Initializing the viewer on specific HTML tags.

+ 67 - 0
Viewer/dist/eventsExample.html

@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html lang="en">
+
+    <head>
+        <meta charset="UTF-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1.0">
+        <meta http-equiv="X-UA-Compatible" content="ie=edge">
+        <title>BabylonJS Viewer - Basic usage</title>
+        <style>
+            babylon {
+                max-width: 800px;
+                max-height: 500px;
+                width: 100%;
+                height: 600px;
+            }
+        </style>
+    </head>
+
+    <body>
+        <babylon id="babylon-viewer" model.title="Amazing Rabbit" model.subtitle="BabylonJS" model.thumbnail="https://www.babylonjs.com/img/favicon/apple-icon-144x144.png"
+            model.url="https://playground.babylonjs.com/scenes/Rabbit.babylon" observers.on-scene-init="globalSceneInitCallback"></babylon>
+        <script src="viewer.js"></script>
+        <script>
+            //get by id ONLY after viewer init
+            var willNotWork = BabylonViewer.viewerManager.getViewerById('babylon-viewer');
+            console.log('viewer not yet initialized');
+
+            // Pomise-based API:
+            BabylonViewer.viewerManager.getViewerPromiseById('babylon-viewer').then(function (viewer) {
+                // this will resolve only after the viewer with this specific ID is initialized
+                console.log('Using promises: ', 'viewer - ' + viewer.getBaseId());
+
+                viewerObservables(viewer);
+            });
+
+            // call back variant:
+            BabylonViewer.viewerManager.onViewerAdded = function (viewer) {
+                console.log('Using viewerManager.onViewerAdded: ', 'viewer - ' + viewer.getBaseId());
+            }
+
+            // using observers:
+            BabylonViewer.viewerManager.onViewerAddedObservable.add(function (viewer) {
+                console.log('Using viewerManager.onViewerAddedObservable: ', 'viewer - ' + viewer.getBaseId());
+            });
+
+            function viewerObservables(viewer) {
+                viewer.onEngineInitObservable.add(function (engine) {
+                    console.log('Engine initialized');
+                });
+
+                viewer.onSceneInitObservable.add(function (scene) {
+                    console.log('Scene initialized');
+                });
+
+                viewer.onModelLoadedObservable.add(function (meshes) {
+                    console.log('Model loaded');
+                });
+            }
+
+            function globalSceneInitCallback(scene) {
+                console.log('scene-init function defined in the configuration');
+            }
+
+        </script>
+    </body>
+
+</html>

Plik diff jest za duży
+ 3452 - 1657
Viewer/dist/viewer.js


+ 8 - 8
Viewer/package.json

@@ -1,6 +1,6 @@
 {
     "name": "babylonjs-viewer",
-    "version": "0.1.0",
+    "version": "0.2.0",
     "description": "A viewer using BabylonJS to display 3D elements natively",
     "scripts": {
         "start:server": "webpack-dev-server",
@@ -23,7 +23,7 @@
     },
     "homepage": "https://github.com/BabylonJS/Babylon.js#readme",
     "devDependencies": {
-        "@types/node": "^8.0.47",
+        "@types/node": "^8.0.51",
         "base64-image-loader": "^1.2.0",
         "html-loader": "^0.5.1",
         "json-loader": "^0.5.7",
@@ -34,15 +34,15 @@
         "webpack-dev-server": "^2.9.4"
     },
     "dependencies": {
-        "babylonjs": "^3.1.0-alpha3.7",
-        "babylonjs-loaders": "^3.1.0-alpha3.7",
-        "babylonjs-materials": "^3.1.0-alpha3.7",
-        "babylonjs-post-process": "^3.1.0-alpha3.7",
-        "babylonjs-procedural-textures": "^3.1.0-alpha3.7",
+        "babylonjs": "^3.1.0-beta1.1.1",
+        "babylonjs-loaders": "^3.1.0-beta1.1",
+        "babylonjs-materials": "^3.1.0-beta1.1",
+        "babylonjs-post-process": "^3.1.0-beta1.1",
+        "babylonjs-procedural-textures": "^3.1.0-beta1.1",
         "es6-promise": "^4.1.1",
         "handlebars": "^4.0.11",
         "lodash": "^4.17.4",
         "lodash.merge": "^4.6.0",
         "promise-polyfill": "^6.0.2"
     }
-}
+}

+ 12 - 3
Viewer/src/configuration/configuration.ts

@@ -13,7 +13,8 @@ export interface ViewerConfiguration {
         mapper?: string; // json (default), html, yaml, xml, etc'. if not provided, file extension will be used.
     };
 
-    // native (!!!) javascript events. Mainly used in the JSON-format.
+    // Deprecated
+    /*// native (!!!) javascript events. Mainly used in the JSON-format.
     // those events will be triggered by the container element (the <babylon> tag);
     events?: {
         load: boolean | string;
@@ -23,8 +24,15 @@ export interface ViewerConfiguration {
         pointerup: boolean | string;
         pointermove: boolean | string;
         // load: 'onViewerLoaded' // will trigger the event prefix-onViewerLoaded instead of prefix-onLoad (and ONLY this event).
-    } | boolean; //events: true - fire all events
-    eventPrefix?: string;
+    } | boolean; //events: true - fire all events*/
+    //eventPrefix?: string;
+
+    // names of functions in the window context.
+    observers?: {
+        onEngineInit?: string;
+        onSceneInit?: string;
+        onModelLoaded?: string;
+    }
 
     canvasElement?: string; // if there is a need to override the standard implementation - ID of HTMLCanvasElement
 
@@ -46,6 +54,7 @@ export interface ViewerConfiguration {
     };
 
     scene?: {
+        debug?: boolean;
         autoRotate?: boolean;
         rotationSpeed?: number;
         defaultCamera?: boolean;

+ 2 - 2
Viewer/src/configuration/types/default.ts

@@ -2,8 +2,8 @@ import { ViewerConfiguration } from './../configuration';
 
 export let defaultConfiguration: ViewerConfiguration = {
     version: "0.1",
-    eventPrefix: 'babylonviewer-',
-    events: true,
+    //eventPrefix: 'babylonviewer-',
+    //events: true,
     templates: {
         main: {
             html: require("../../../assets/templates/default/defaultTemplate.html")

+ 39 - 0
Viewer/src/util/promiseObservable.ts

@@ -0,0 +1,39 @@
+import { Observable, Nullable, Observer } from "babylonjs";
+
+export class PromiseObservable<T> extends Observable<T> {
+
+    public notifyWithPromise(eventData: T, mask: number = -1, target?: any, currentTarget?: any): Promise<any> {
+
+        let p = Promise.resolve();
+
+        if (!this._observers.length) {
+            return p;
+        }
+
+        let state = this['_eventState'];
+        state.mask = mask;
+        state.target = target;
+        state.currentTarget = currentTarget;
+        state.skipNextObservers = false;
+
+        this._observers.forEach(obs => {
+            if (state.skipNextObservers) {
+                return;
+            }
+            if (obs.mask & mask) {
+                if (obs.scope) {
+                    // TODO - I can add the variable from the last function here. Requires changing callback sig
+                    p = p.then(() => {
+                        return obs.callback.apply(obs.scope, [eventData, state]);
+                    });
+                } else {
+                    p = p.then(() => {
+                        return obs.callback(eventData, state);
+                    });
+                }
+            }
+        });
+
+        return p;
+    }
+}

+ 7 - 1
Viewer/src/viewer/defaultViewer.ts

@@ -1,3 +1,4 @@
+import { ViewerConfiguration } from './../configuration/configuration';
 import { Template } from './../templateManager';
 import { AbstractViewer } from './viewer';
 import { Observable, ShadowLight, CubeTexture, BouncingBehavior, FramingBehavior, Behavior, Light, Engine, Scene, AutoRotationBehavior, AbstractMesh, Quaternion, StandardMaterial, ShadowOnlyMaterial, ArcRotateCamera, ImageProcessingConfiguration, Color3, Vector3, SceneLoader, Mesh, HemisphericLight } from 'babylonjs';
@@ -11,6 +12,11 @@ export class DefaultViewer extends AbstractViewer {
 
     public camera: ArcRotateCamera;
 
+    constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = { extends: 'default' }) {
+        super(containerElement, initialConfiguration);
+        this.onModelLoadedObservable.add(this.onModelLoaded);
+    }
+
     public initScene(): Promise<Scene> {
         return super.initScene().then(() => {
             this.extendClassWithConfig(this.scene, this.configuration.scene);
@@ -132,7 +138,7 @@ export class DefaultViewer extends AbstractViewer {
         });
     }
 
-    public onModelLoaded(meshes: Array<AbstractMesh>) {
+    private onModelLoaded = (meshes: Array<AbstractMesh>) => {
 
         // here we could set the navbar's model information:
         this.setModelMetaData();

+ 36 - 11
Viewer/src/viewer/viewer.ts

@@ -3,6 +3,7 @@ import { TemplateManager } from './../templateManager';
 import configurationLoader from './../configuration/loader';
 import { Observable, Engine, Scene, ArcRotateCamera, Vector3, SceneLoader, AbstractMesh, Mesh, HemisphericLight } from 'babylonjs';
 import { ViewerConfiguration } from '../configuration/configuration';
+import { PromiseObservable } from '../util/promiseObservable';
 
 export abstract class AbstractViewer {
 
@@ -14,6 +15,11 @@ export abstract class AbstractViewer {
 
     protected configuration: ViewerConfiguration;
 
+    // observables
+    public onSceneInitObservable: PromiseObservable<Scene>;
+    public onEngineInitObservable: PromiseObservable<Engine>;
+    public onModelLoadedObservable: PromiseObservable<AbstractMesh[]>;
+
     constructor(public containerElement: HTMLElement, initialConfiguration: ViewerConfiguration = {}) {
         // if exists, use the container id. otherwise, generate a random string.
         if (containerElement.id) {
@@ -22,6 +28,10 @@ export abstract class AbstractViewer {
             this.baseId = containerElement.id = 'bjs' + Math.random().toString(32).substr(2, 8);
         }
 
+        this.onSceneInitObservable = new PromiseObservable();
+        this.onEngineInitObservable = new PromiseObservable();
+        this.onModelLoadedObservable = new PromiseObservable();
+
         // add this viewer to the viewer manager
         viewerManager.addViewer(this);
 
@@ -33,6 +43,20 @@ export abstract class AbstractViewer {
         // extend the configuration
         configurationLoader.loadConfiguration(initialConfiguration).then((configuration) => {
             this.configuration = configuration;
+
+            // adding preconfigured functions
+            if (this.configuration.observers) {
+                if (this.configuration.observers.onEngineInit) {
+                    this.onEngineInitObservable.add(window[this.configuration.observers.onEngineInit]);
+                }
+                if (this.configuration.observers.onSceneInit) {
+                    this.onSceneInitObservable.add(window[this.configuration.observers.onSceneInit]);
+                }
+                if (this.configuration.observers.onModelLoaded) {
+                    this.onModelLoadedObservable.add(window[this.configuration.observers.onModelLoaded]);
+                }
+            }
+
             // initialize the templates
             let templateConfiguration = this.configuration.templates || {};
             this.templateManager.initTemplate(templateConfiguration);
@@ -93,7 +117,9 @@ export abstract class AbstractViewer {
         var scale = Math.max(0.5, 1 / (window.devicePixelRatio || 2));
         this.engine.setHardwareScalingLevel(scale);
 
-        return Promise.resolve(this.engine);
+        return this.onEngineInitObservable.notifyWithPromise(this.engine).then(() => {
+            return this.engine;
+        });
     }
 
     protected initScene(): Promise<Scene> {
@@ -107,7 +133,12 @@ export abstract class AbstractViewer {
         this.scene = new Scene(this.engine);
         // make sure there is a default camera and light.
         this.scene.createDefaultCameraOrLight(true, true, true);
-        return Promise.resolve(this.scene);
+        if (this.configuration.scene && this.configuration.scene.debug) {
+            this.scene.debugLayer.show();
+        }
+        return this.onSceneInitObservable.notifyWithPromise(this.scene).then(() => {
+            return this.scene;
+        });
     }
 
     public loadModel(model: any = this.configuration.model, clearScene: boolean = true): Promise<Scene> {
@@ -130,15 +161,9 @@ export abstract class AbstractViewer {
                 }, plugin);
             });
         }).then((meshes: Array<AbstractMesh>) => {
-            return this.onModelLoaded(meshes);
+            return this.onModelLoadedObservable.notifyWithPromise(meshes).then(() => {
+                return this.scene;
+            });
         });
     }
-
-    protected onModelLoaded(meshes: Array<AbstractMesh>): Promise<Scene> {
-        console.log("model loaded");
-        return Promise.resolve(this.scene);
-    }
-
-    public abstract initEnvironment(): Promise<Scene>;
-
 }

+ 23 - 0
Viewer/src/viewer/viewerManager.ts

@@ -1,15 +1,21 @@
+import { Observable } from 'babylonjs';
 import { AbstractViewer } from './viewer';
 
 class ViewerManager {
 
     private viewers: { [key: string]: AbstractViewer };
 
+    public onViewerAdded: (viewer: AbstractViewer) => void;
+    public onViewerAddedObservable: Observable<AbstractViewer>;
+
     constructor() {
         this.viewers = {};
+        this.onViewerAddedObservable = new Observable();
     }
 
     public addViewer(viewer: AbstractViewer) {
         this.viewers[viewer.getBaseId()] = viewer;
+        this._onViewerAdded(viewer);
     }
 
     public getViewerById(id: string): AbstractViewer {
@@ -23,6 +29,23 @@ class ViewerManager {
             }
         }
     }
+
+    public getViewerPromiseById(id: string): Promise<AbstractViewer> {
+        return new Promise((resolve, reject) => {
+            let viewerFunction = (viewer: AbstractViewer) => {
+                if (viewer.getBaseId() === id) {
+                    resolve(viewer);
+                    this.onViewerAddedObservable.removeCallback(viewerFunction);
+                }
+            }
+            this.onViewerAddedObservable.add(viewerFunction);
+        });
+    }
+
+    private _onViewerAdded(viewer: AbstractViewer) {
+        this.onViewerAdded && this.onViewerAdded(viewer);
+        this.onViewerAddedObservable.notifyObservers(viewer);
+    }
 }
 
 export let viewerManager = new ViewerManager();

Plik diff jest za duży
+ 2227 - 2197
dist/preview release/babylon.d.ts


Plik diff jest za duży
+ 41 - 41
dist/preview release/babylon.js


Plik diff jest za duży
+ 1001 - 965
dist/preview release/babylon.max.js


Plik diff jest za duży
+ 2227 - 2197
dist/preview release/babylon.module.d.ts


Plik diff jest za duży
+ 41 - 41
dist/preview release/babylon.worker.js


Plik diff jest za duży
+ 10145 - 10115
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


Plik diff jest za duży
+ 38 - 38
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


Plik diff jest za duży
+ 1008 - 979
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


Plik diff jest za duży
+ 10145 - 10115
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


+ 6 - 0
dist/preview release/gui/babylon.gui.js

@@ -156,9 +156,15 @@ var BABYLON;
             });
             Object.defineProperty(AdvancedDynamicTexture.prototype, "isForeground", {
                 get: function () {
+                    if (!this.layer) {
+                        return true;
+                    }
                     return (!this.layer.isBackground);
                 },
                 set: function (value) {
+                    if (!this.layer) {
+                        return;
+                    }
                     if (this.layer.isBackground === !value) {
                         return;
                     }

Plik diff jest za duży
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


Plik diff jest za duży
+ 1 - 1
dist/preview release/loaders/babylon.objFileLoader.min.js


Plik diff jest za duży
+ 2 - 2
dist/preview release/loaders/babylonjs.loaders.min.js


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

@@ -22,6 +22,7 @@
 - Complete rework of Unity3D exporter. [Doc here](http://doc.babylonjs.com/resources/intro) ([MackeyK24](https://github.com/MackeyK24))
 
 ## Updates
+- Introduced `TransformNode` class as a parent of `AbstractMesh`. This class was extensively asked by the community to hold only tranformation for a node ([deltakosh](https://github.com/deltakosh))
 - Added `boundingInfo.centerOn` to recreate the bounding info to be centered around a specific point given a specific extend ([deltakosh](https://github.com/deltakosh))
 - Added `mesh.normalizeToUnitCube` to uniformly scales the mesh to fit inside of a unit cube (1 X 1 X 1 units) ([deltakosh](https://github.com/deltakosh))
 - Added `scene.onDataLoadedObservable` which is raised when SceneLoader.Append or SceneLoader.Load or SceneLoader.ImportMesh were successfully executed ([deltakosh](https://github.com/deltakosh))

+ 6 - 0
gui/src/advancedDynamicTexture.ts

@@ -115,10 +115,16 @@ module BABYLON.GUI {
         }
         
         public get isForeground(): boolean {
+            if (!this.layer) {
+                return true;
+            }
             return (!this.layer.isBackground);
         }
 
         public set isForeground(value: boolean) {
+            if (!this.layer) {
+                return;
+            }            
             if (this.layer.isBackground === !value) {
                 return;
             }

+ 32 - 30
src/Engine/babylon.engine.ts

@@ -4827,40 +4827,42 @@
             this.disableVR();
 
             // Events
-            window.removeEventListener("blur", this._onBlur);
-            window.removeEventListener("focus", this._onFocus);
-            window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
-            window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
-            if (this._renderingCanvas) {
-                this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
-                this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);
-                this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
+            if (Tools.IsWindowObjectExist()) {
+                window.removeEventListener("blur", this._onBlur);
+                window.removeEventListener("focus", this._onFocus);
+                window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
+                window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
+                if (this._renderingCanvas) {
+                    this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
+                    this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);
+                    this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
 
-                if (!this._doNotHandleContextLost) {
-                    this._renderingCanvas.removeEventListener("webglcontextlost", this._onContextLost);
-                    this._renderingCanvas.removeEventListener("webglcontextrestored", this._onContextRestored);
-                }
-            }
-            document.removeEventListener("fullscreenchange", this._onFullscreenChange);
-            document.removeEventListener("mozfullscreenchange", this._onFullscreenChange);
-            document.removeEventListener("webkitfullscreenchange", this._onFullscreenChange);
-            document.removeEventListener("msfullscreenchange", this._onFullscreenChange);
-            document.removeEventListener("pointerlockchange", this._onPointerLockChange);
-            document.removeEventListener("mspointerlockchange", this._onPointerLockChange);
-            document.removeEventListener("mozpointerlockchange", this._onPointerLockChange);
-            document.removeEventListener("webkitpointerlockchange", this._onPointerLockChange);
-
-            if (this._onVrDisplayConnect) {
-                window.removeEventListener('vrdisplayconnect', this._onVrDisplayConnect);
-                if (this._onVrDisplayDisconnect) {
-                    window.removeEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
+                    if (!this._doNotHandleContextLost) {
+                        this._renderingCanvas.removeEventListener("webglcontextlost", this._onContextLost);
+                        this._renderingCanvas.removeEventListener("webglcontextrestored", this._onContextRestored);
+                    }
                 }
+                document.removeEventListener("fullscreenchange", this._onFullscreenChange);
+                document.removeEventListener("mozfullscreenchange", this._onFullscreenChange);
+                document.removeEventListener("webkitfullscreenchange", this._onFullscreenChange);
+                document.removeEventListener("msfullscreenchange", this._onFullscreenChange);
+                document.removeEventListener("pointerlockchange", this._onPointerLockChange);
+                document.removeEventListener("mspointerlockchange", this._onPointerLockChange);
+                document.removeEventListener("mozpointerlockchange", this._onPointerLockChange);
+                document.removeEventListener("webkitpointerlockchange", this._onPointerLockChange);
+
+                if (this._onVrDisplayConnect) {
+                    window.removeEventListener('vrdisplayconnect', this._onVrDisplayConnect);
+                    if (this._onVrDisplayDisconnect) {
+                        window.removeEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
+                    }
 
-                if (this._onVrDisplayPresentChange) {
-                    window.removeEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
+                    if (this._onVrDisplayPresentChange) {
+                        window.removeEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
+                    }
+                    this._onVrDisplayConnect = null;
+                    this._onVrDisplayDisconnect = null;
                 }
-                this._onVrDisplayConnect = null;
-                this._onVrDisplayDisconnect = null;
             }
 
             // Remove from Instances

+ 10 - 0
src/Engine/babylon.nullEngine.ts

@@ -380,5 +380,15 @@
 
             this._bindTextureDirectly(0, texture);
         }
+
+        public _releaseBuffer(buffer: WebGLBuffer): boolean {
+            buffer.references--;
+
+            if (buffer.references === 0) {
+                return true;
+            }
+
+            return false;
+        }        
     }
 }

+ 19 - 566
src/Mesh/babylon.abstractMesh.ts

@@ -1,12 +1,5 @@
 module BABYLON {
-    export class AbstractMesh extends Node implements IDisposable, ICullable, IGetSetVerticesData {
-        // Statics
-        private static _BILLBOARDMODE_NONE = 0;
-        private static _BILLBOARDMODE_X = 1;
-        private static _BILLBOARDMODE_Y = 2;
-        private static _BILLBOARDMODE_Z = 4;
-        private static _BILLBOARDMODE_ALL = 7;
-
+    export class AbstractMesh extends TransformNode implements IDisposable, ICullable, IGetSetVerticesData {
         public static OCCLUSION_TYPE_NONE = 0;
         public static OCCLUSION_TYPE_OPTIMISTIC = 1;
         public static OCCLUSION_TYPE_STRICT = 2;
@@ -14,23 +7,23 @@
         public static OCCLUSION_ALGORITHM_TYPE_CONSERVATIVE = 1;
 
         public static get BILLBOARDMODE_NONE(): number {
-            return AbstractMesh._BILLBOARDMODE_NONE;
+            return TransformNode.BILLBOARDMODE_NONE;
         }
 
         public static get BILLBOARDMODE_X(): number {
-            return AbstractMesh._BILLBOARDMODE_X;
+            return TransformNode.BILLBOARDMODE_X;
         }
 
         public static get BILLBOARDMODE_Y(): number {
-            return AbstractMesh._BILLBOARDMODE_Y;
+            return TransformNode.BILLBOARDMODE_Y;
         }
 
         public static get BILLBOARDMODE_Z(): number {
-            return AbstractMesh._BILLBOARDMODE_Z;
+            return TransformNode.BILLBOARDMODE_Z;
         }
 
         public static get BILLBOARDMODE_ALL(): number {
-            return AbstractMesh._BILLBOARDMODE_ALL;
+            return TransformNode.BILLBOARDMODE_ALL;
         }
 
         // facetData private properties
@@ -110,18 +103,12 @@
             return this._facetDataEnabled;
         }
 
-        // Normal matrix
-        private _nonUniformScaling = false;
-        public get nonUniformScaling(): boolean {
-            return this._nonUniformScaling;
-        }
-
-        public set nonUniformScaling(value: boolean) {
-            if (this._nonUniformScaling === value) {
-                return;
+        public _updateNonUniformScalingState(value: boolean): boolean {
+            if (!super._updateNonUniformScalingState(value)) {
+                return false;
             }
-            this._nonUniformScaling = true;
             this._markSubMeshesAsMiscDirty();
+            return true;
         }
 
         // Events
@@ -155,12 +142,6 @@
         }
 
         /**
-        * An event triggered after the world matrix is updated
-        * @type {BABYLON.Observable}
-        */
-        public onAfterWorldMatrixUpdateObservable = new Observable<AbstractMesh>();
-
-        /**
         * An event triggered when material is changed
         * @type {BABYLON.Observable}
         */
@@ -168,7 +149,6 @@
 
         // Properties
         public definedFacingForward = true; // orientation for POV movement & rotation
-        public position = Vector3.Zero();
 
         /**
         * This property determines the type of occlusion query algorithm to run in WebGl, you can use:
@@ -222,13 +202,8 @@
 
         private _occlusionQuery: Nullable<WebGLQuery>;
 
-        private _rotation = Vector3.Zero();
-        private _rotationQuaternion: Nullable<Quaternion>;
-        private _scaling = Vector3.One();
-        public billboardMode = AbstractMesh.BILLBOARDMODE_NONE;
         public visibility = 1.0;
         public alphaIndex = Number.MAX_VALUE;
-        public infiniteDistance = false;
         public isVisible = true;
         public isPickable = true;
         public showBoundingBox = false;
@@ -345,8 +320,6 @@
             this._markSubMeshesAsMiscDirty();
         }
 
-        public scalingDeterminant = 1;
-
         public useOctreeForRenderingSelection = true;
         public useOctreeForPicking = true;
         public useOctreeForCollisions = true;
@@ -407,27 +380,17 @@
             this._collisionGroup = !isNaN(mask) ? mask : -1;
         }
 
-        // Attach to bone
-        private _meshToBoneReferal: Nullable<AbstractMesh>;
-
         // Edges
         public edgesWidth = 1;
         public edgesColor = new Color4(1, 0, 0, 1);
         public _edgesRenderer: Nullable<EdgesRenderer>;
 
         // Cache
-        private _localWorld = Matrix.Zero();
-        public _worldMatrix = Matrix.Zero();
-        private _absolutePosition = Vector3.Zero();
         private _collisionsTransformMatrix = Matrix.Zero();
         private _collisionsScalingMatrix = Matrix.Zero();
-        private _isDirty = false;
         public _masterMesh: Nullable<AbstractMesh>;
 
         public _boundingInfo: Nullable<BoundingInfo>;
-        private _pivotMatrix = Matrix.Identity();
-        private _pivotMatrixInverse: Matrix;
-        private _postMultiplyPivotMatrix = false;
         public _isDisposed = false;
         public _renderId = 0;
 
@@ -435,12 +398,8 @@
         public _submeshesOctree: Octree<SubMesh>;
         public _intersectionsInProgress = new Array<AbstractMesh>();
 
-        private _isWorldMatrixFrozen = false;
-
         public _unIndexed = false;
 
-        public _poseMatrix: Matrix;
-
         public _lightSources = new Array<Light>();
 
         public get _positions(): Nullable<Vector3[]> {
@@ -612,20 +571,7 @@
             }
         }
 
-        /**
-         * Rotation property : a Vector3 depicting the rotation value in radians around each local axis X, Y, Z. 
-         * If rotation quaternion is set, this Vector3 will (almost always) be the Zero vector!
-         * Default : (0.0, 0.0, 0.0)
-         */
-        public get rotation(): Vector3 {
-            return this._rotation;
-        }
-
-        public set rotation(newRotation: Vector3) {
-            this._rotation = newRotation;
-        }
-
-        /**
+         /**
          * Scaling property : a Vector3 depicting the mesh scaling along each local axis X, Y, Z.  
          * Default : (1.0, 1.0, 1.0)
          */
@@ -633,6 +579,10 @@
             return this._scaling;
         }
 
+        /**
+         * Scaling property : a Vector3 depicting the mesh scaling along each local axis X, Y, Z.  
+         * Default : (1.0, 1.0, 1.0)
+         */
         public set scaling(newScaling: Vector3) {
             this._scaling = newScaling;
             if (this.physicsImpostor) {
@@ -640,23 +590,6 @@
             }
         }
 
-        /**
-         * Rotation Quaternion property : this a Quaternion object depicting the mesh rotation by using a unit quaternion. 
-         * It's null by default.  
-         * If set, only the rotationQuaternion is then used to compute the mesh rotation and its property `.rotation\ is then ignored and set to (0.0, 0.0, 0.0)
-         */
-        public get rotationQuaternion(): Nullable<Quaternion> {
-            return this._rotationQuaternion;
-        }
-
-        public set rotationQuaternion(quaternion: Nullable<Quaternion>) {
-            this._rotationQuaternion = quaternion;
-            //reset the rotation vector. 
-            if (quaternion && this.rotation.length()) {
-                this.rotation.copyFromFloats(0.0, 0.0, 0.0);
-            }
-        }
-
         // Methods
         /**
          * Copies the paramater passed Matrix into the mesh Pose matrix.  
@@ -878,54 +811,7 @@
                 return this._masterMesh.getWorldMatrix();
             }
 
-            if (this._currentRenderId !== this.getScene().getRenderId()) {
-                this.computeWorldMatrix();
-            }
-            return this._worldMatrix;
-        }
-
-        /**
-         * Returns directly the latest state of the mesh World matrix. 
-         * A Matrix is returned.    
-         */
-        public get worldMatrixFromCache(): Matrix {
-            return this._worldMatrix;
-        }
-
-        /**
-         * Returns the current mesh absolute position.
-         * Retuns a Vector3.
-         */
-        public get absolutePosition(): Vector3 {
-            return this._absolutePosition;
-        }
-        /**
-         * Prevents the World matrix to be computed any longer.
-         * Returns the AbstractMesh.  
-         */
-        public freezeWorldMatrix(): AbstractMesh {
-            this._isWorldMatrixFrozen = false;  // no guarantee world is not already frozen, switch off temporarily
-            this.computeWorldMatrix(true);
-            this._isWorldMatrixFrozen = true;
-            return this;
-        }
-
-        /**
-         * Allows back the World matrix computation. 
-         * Returns the AbstractMesh.  
-         */
-        public unfreezeWorldMatrix() {
-            this._isWorldMatrixFrozen = false;
-            this.computeWorldMatrix(true);
-            return this;
-        }
-
-        /**
-         * True if the World matrix has been frozen.  
-         * Returns a boolean.  
-         */
-        public get isWorldMatrixFrozen(): boolean {
-            return this._isWorldMatrixFrozen;
+            return super.getWorldMatrix();
         }
 
         private static _rotationAxisCache = new Quaternion();
@@ -1036,51 +922,7 @@
             return this;
         }
 
-        /**
-         * Retuns the mesh absolute position in the World.  
-         * Returns a Vector3.
-         */
-        public getAbsolutePosition(): Vector3 {
-            this.computeWorldMatrix();
-            return this._absolutePosition;
-        }
-
-        /**
-         * Sets the mesh absolute position in the World from a Vector3 or an Array(3).
-         * Returns the AbstractMesh.  
-         */
-        public setAbsolutePosition(absolutePosition: Vector3): AbstractMesh {
-            if (!absolutePosition) {
-                return this;
-            }
-            var absolutePositionX;
-            var absolutePositionY;
-            var absolutePositionZ;
-            if (absolutePosition.x === undefined) {
-                if (arguments.length < 3) {
-                    return this;
-                }
-                absolutePositionX = arguments[0];
-                absolutePositionY = arguments[1];
-                absolutePositionZ = arguments[2];
-            }
-            else {
-                absolutePositionX = absolutePosition.x;
-                absolutePositionY = absolutePosition.y;
-                absolutePositionZ = absolutePosition.z;
-            }
-            if (this.parent) {
-                var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
-                invertParentWorldMatrix.invert();
-                var worldPosition = new Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
-                this.position = Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
-            } else {
-                this.position.x = absolutePositionX;
-                this.position.y = absolutePositionY;
-                this.position.z = absolutePositionZ;
-            }
-            return this;
-        }
+   
 
         // ================================== Point of View Movement =================================
         /**
@@ -1147,30 +989,6 @@
             return new Vector3(flipBack * defForwardMult, twirlClockwise, tiltRight * defForwardMult);
         }
 
-        /**
-         * Sets a new pivot matrix to the mesh.  
-         * Returns the AbstractMesh.
-         */
-        public setPivotMatrix(matrix: Matrix, postMultiplyPivotMatrix = false): AbstractMesh {
-            this._pivotMatrix = matrix.clone();
-            this._cache.pivotMatrixUpdated = true;
-            this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
-
-            if (this._postMultiplyPivotMatrix) {
-                this._pivotMatrixInverse = Matrix.Invert(matrix);
-            }
-            return this;
-        }
-
-        /**
-         * Returns the mesh pivot matrix.
-         * Default : Identity.  
-         * A Matrix is returned.  
-         */
-        public getPivotMatrix(): Matrix {
-            return this._pivotMatrix;
-        }
-
         public _isSynchronized(): boolean {
             if (this._isDirty) {
                 return false;
@@ -1299,173 +1117,9 @@
             return this;
         }
 
-        /**
-         * Computes the mesh World matrix and returns it.  
-         * If the mesh world matrix is frozen, this computation does nothing more than returning the last frozen values.  
-         * If the parameter `force` is let to `false` (default), the current cached World matrix is returned. 
-         * If the parameter `force`is set to `true`, the actual computation is done.  
-         * Returns the mesh World Matrix.
-         */
-        public computeWorldMatrix(force?: boolean): Matrix {
-            if (this._isWorldMatrixFrozen) {
-                return this._worldMatrix;
-            }
-
-            if (!force && this.isSynchronized(true)) {
-                return this._worldMatrix;
-            }
-
-            this._cache.position.copyFrom(this.position);
-            this._cache.scaling.copyFrom(this.scaling);
-            this._cache.pivotMatrixUpdated = false;
-            this._cache.billboardMode = this.billboardMode;
-            this._currentRenderId = this.getScene().getRenderId();
-            this._isDirty = false;
-
-            // Scaling
-            Matrix.ScalingToRef(this.scaling.x * this.scalingDeterminant, this.scaling.y * this.scalingDeterminant, this.scaling.z * this.scalingDeterminant, Tmp.Matrix[1]);
-
-            // Rotation
-
-            //rotate, if quaternion is set and rotation was used
-            if (this.rotationQuaternion) {
-                var len = this.rotation.length();
-                if (len) {
-                    this.rotationQuaternion.multiplyInPlace(BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z))
-                    this.rotation.copyFromFloats(0, 0, 0);
-                }
-            }
-
-            if (this.rotationQuaternion) {
-                this.rotationQuaternion.toRotationMatrix(Tmp.Matrix[0]);
-                this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
-            } else {
-                Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, Tmp.Matrix[0]);
-                this._cache.rotation.copyFrom(this.rotation);
-            }
-
-            // Translation
-            let camera = (<Camera>this.getScene().activeCamera);
-            
-            if (this.infiniteDistance && !this.parent && camera) {
-
-                var cameraWorldMatrix = camera.getWorldMatrix();
-
-                var cameraGlobalPosition = new Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
-
-                Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y,
-                    this.position.z + cameraGlobalPosition.z, Tmp.Matrix[2]);
-            } else {
-                Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, Tmp.Matrix[2]);
-            }
-
-            // Composing transformations
-            this._pivotMatrix.multiplyToRef(Tmp.Matrix[1], Tmp.Matrix[4]);
-            Tmp.Matrix[4].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[5]);
-
-            // Billboarding (testing PG:http://www.babylonjs-playground.com/#UJEIL#13)
-            if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE && camera) {
-                if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_ALL) !== AbstractMesh.BILLBOARDMODE_ALL) {
-                    // Need to decompose each rotation here
-                    var currentPosition = Tmp.Vector3[3];
-
-                    if (this.parent && this.parent.getWorldMatrix) {
-                        if (this._meshToBoneReferal) {
-                            this.parent.getWorldMatrix().multiplyToRef(this._meshToBoneReferal.getWorldMatrix(), Tmp.Matrix[6]);
-                            Vector3.TransformCoordinatesToRef(this.position, Tmp.Matrix[6], currentPosition);
-                        } else {
-                            Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), currentPosition);
-                        }
-                    } else {
-                        currentPosition.copyFrom(this.position);
-                    }
-
-                    currentPosition.subtractInPlace(camera.globalPosition);
-
-                    var finalEuler = Tmp.Vector3[4].copyFromFloats(0, 0, 0);
-                    if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_X) === AbstractMesh.BILLBOARDMODE_X) {
-                        finalEuler.x = Math.atan2(-currentPosition.y, currentPosition.z);
-                    }
-
-                    if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_Y) === AbstractMesh.BILLBOARDMODE_Y) {
-                        finalEuler.y = Math.atan2(currentPosition.x, currentPosition.z);
-                    }
-
-                    if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_Z) === AbstractMesh.BILLBOARDMODE_Z) {
-                        finalEuler.z = Math.atan2(currentPosition.y, currentPosition.x);
-                    }
-
-                    Matrix.RotationYawPitchRollToRef(finalEuler.y, finalEuler.x, finalEuler.z, Tmp.Matrix[0]);
-                } else {
-                    Tmp.Matrix[1].copyFrom(camera.getViewMatrix());
-
-                    Tmp.Matrix[1].setTranslationFromFloats(0, 0, 0);
-                    Tmp.Matrix[1].invertToRef(Tmp.Matrix[0]);
-                }
-
-                Tmp.Matrix[1].copyFrom(Tmp.Matrix[5]);
-                Tmp.Matrix[1].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[5]);
-            }
-
-            // Local world
-            Tmp.Matrix[5].multiplyToRef(Tmp.Matrix[2], this._localWorld);
-
-            // Parent
-            if (this.parent && this.parent.getWorldMatrix) {
-                if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE) {
-                    if (this._meshToBoneReferal) {
-                        this.parent.getWorldMatrix().multiplyToRef(this._meshToBoneReferal.getWorldMatrix(), Tmp.Matrix[6]);
-                        Tmp.Matrix[5].copyFrom(Tmp.Matrix[6]);
-                    } else {
-                        Tmp.Matrix[5].copyFrom(this.parent.getWorldMatrix());
-                    }
-
-                    this._localWorld.getTranslationToRef(Tmp.Vector3[5]);
-                    Vector3.TransformCoordinatesToRef(Tmp.Vector3[5], Tmp.Matrix[5], Tmp.Vector3[5]);
-                    this._worldMatrix.copyFrom(this._localWorld);
-                    this._worldMatrix.setTranslation(Tmp.Vector3[5]);
-
-                } else {
-                    if (this._meshToBoneReferal) {
-                        this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), Tmp.Matrix[6]);
-                        Tmp.Matrix[6].multiplyToRef(this._meshToBoneReferal.getWorldMatrix(), this._worldMatrix);
-                    } else {
-                        this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
-                    }
-                }
-                this._markSyncedWithParent();
-            } else {
-                this._worldMatrix.copyFrom(this._localWorld);
-            }
-
-            // Post multiply inverse of pivotMatrix
-            if (this._postMultiplyPivotMatrix) {
-                this._worldMatrix.multiplyToRef(this._pivotMatrixInverse, this._worldMatrix);
-            }
-
-            // Normal matrix
-            if (this.scaling.isNonUniform) {
-                this.nonUniformScaling = true;
-            } else if (this.parent && (<AbstractMesh>this.parent)._nonUniformScaling) {
-                this.nonUniformScaling = (<AbstractMesh>this.parent)._nonUniformScaling;
-            } else {
-                this.nonUniformScaling = false;
-            }
-
+        protected _afterComputeWorldMatrix(): void {
             // Bounding info
             this._updateBoundingInfo();
-
-            // Absolute position
-            this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
-
-            // Callbacks
-            this.onAfterWorldMatrixUpdateObservable.notifyObservers(this);
-
-            if (!this._poseMatrix) {
-                this._poseMatrix = Matrix.Invert(this._worldMatrix);
-            }
-
-            return this._worldMatrix;
         }
 
         /**
@@ -1489,81 +1143,6 @@
         }
 
         /**
-         * Sets the mesh position in its local space.  
-         * Returns the AbstractMesh.  
-         */
-        public setPositionWithLocalVector(vector3: Vector3): AbstractMesh {
-            this.computeWorldMatrix();
-            this.position = Vector3.TransformNormal(vector3, this._localWorld);
-            return this;
-        }
-
-        /**
-         * Returns the mesh position in the local space from the current World matrix values.
-         * Returns a new Vector3.
-         */
-        public getPositionExpressedInLocalSpace(): Vector3 {
-            this.computeWorldMatrix();
-            var invLocalWorldMatrix = this._localWorld.clone();
-            invLocalWorldMatrix.invert();
-
-            return Vector3.TransformNormal(this.position, invLocalWorldMatrix);
-        }
-
-        /**
-         * Translates the mesh along the passed Vector3 in its local space.  
-         * Returns the AbstractMesh. 
-         */
-        public locallyTranslate(vector3: Vector3): AbstractMesh {
-            this.computeWorldMatrix(true);
-            this.position = Vector3.TransformCoordinates(vector3, this._localWorld);
-            return this;
-        }
-
-        private static _lookAtVectorCache = new Vector3(0, 0, 0);
-        public lookAt(targetPoint: Vector3, yawCor: number = 0, pitchCor: number = 0, rollCor: number = 0, space: Space = Space.LOCAL): AbstractMesh {
-            /// <summary>Orients a mesh towards a target point. Mesh must be drawn facing user.</summary>
-            /// <param name="targetPoint" type="Vector3">The position (must be in same space as current mesh) to look at</param>
-            /// <param name="yawCor" type="Number">optional yaw (y-axis) correction in radians</param>
-            /// <param name="pitchCor" type="Number">optional pitch (x-axis) correction in radians</param>
-            /// <param name="rollCor" type="Number">optional roll (z-axis) correction in radians</param>
-            /// <returns>Mesh oriented towards targetMesh</returns>
-
-            var dv = AbstractMesh._lookAtVectorCache;
-            var pos = space === Space.LOCAL ? this.position : this.getAbsolutePosition();
-            targetPoint.subtractToRef(pos, dv);
-            var yaw = -Math.atan2(dv.z, dv.x) - Math.PI / 2;
-            var len = Math.sqrt(dv.x * dv.x + dv.z * dv.z);
-            var pitch = Math.atan2(dv.y, len);
-            this.rotationQuaternion = this.rotationQuaternion || new Quaternion();
-            Quaternion.RotationYawPitchRollToRef(yaw + yawCor, pitch + pitchCor, rollCor, this.rotationQuaternion);
-            return this;
-        }
-
-        public attachToBone(bone: Bone, affectedMesh: AbstractMesh): AbstractMesh {
-            this._meshToBoneReferal = affectedMesh;
-            this.parent = bone;
-
-            if (bone.getWorldMatrix().determinant() < 0) {
-                this.scalingDeterminant *= -1;
-            }
-            return this;
-        }
-
-        public detachFromBone(): AbstractMesh {
-            if (!this.parent) {
-                return this;
-            }
-
-            if (this.parent.getWorldMatrix().determinant() < 0) {
-                this.scalingDeterminant *= -1;
-            }
-            this._meshToBoneReferal = null;
-            this.parent = null;
-            return this;
-        }
-
-        /**
          * Returns `true` if the mesh is within the frustum defined by the passed array of planes.  
          * A mesh is in the frustum if its bounding box intersects the frustum.  
          * Boolean returned.  
@@ -2055,120 +1634,7 @@
             this._isDisposed = true;
 
             super.dispose();
-        }
-
-        /**
-         * Returns a new Vector3 what is the localAxis, expressed in the mesh local space, rotated like the mesh.  
-         * This Vector3 is expressed in the World space.  
-         */
-        public getDirection(localAxis: Vector3): Vector3 {
-            var result = Vector3.Zero();
-
-            this.getDirectionToRef(localAxis, result);
-
-            return result;
-        }
-
-        /**
-         * Sets the Vector3 "result" as the rotated Vector3 "localAxis" in the same rotation than the mesh.
-         * localAxis is expressed in the mesh local space.
-         * result is computed in the Wordl space from the mesh World matrix.  
-         * Returns the AbstractMesh.  
-         */
-        public getDirectionToRef(localAxis: Vector3, result: Vector3): AbstractMesh {
-            Vector3.TransformNormalToRef(localAxis, this.getWorldMatrix(), result);
-            return this;
-        }
-
-        public setPivotPoint(point: Vector3, space: Space = Space.LOCAL): AbstractMesh {
-
-            if (this.getScene().getRenderId() == 0) {
-                this.computeWorldMatrix(true);
-            }
-
-            var wm = this.getWorldMatrix();
-
-            if (space == Space.WORLD) {
-                var tmat = Tmp.Matrix[0];
-                wm.invertToRef(tmat);
-                point = Vector3.TransformCoordinates(point, tmat);
-            }
-
-            Vector3.TransformCoordinatesToRef(point, wm, this.position);
-            this._pivotMatrix.m[12] = -point.x;
-            this._pivotMatrix.m[13] = -point.y;
-            this._pivotMatrix.m[14] = -point.z;
-            this._cache.pivotMatrixUpdated = true;
-            return this;
-        }
-
-        /**
-         * Returns a new Vector3 set with the mesh pivot point coordinates in the local space.  
-         */
-        public getPivotPoint(): Vector3 {
-            var point = Vector3.Zero();
-            this.getPivotPointToRef(point);
-            return point;
-        }
-
-        /**
-         * Sets the passed Vector3 "result" with the coordinates of the mesh pivot point in the local space.   
-         * Returns the AbstractMesh.   
-         */
-        public getPivotPointToRef(result: Vector3): AbstractMesh {
-            result.x = -this._pivotMatrix.m[12];
-            result.y = -this._pivotMatrix.m[13];
-            result.z = -this._pivotMatrix.m[14];
-            return this;
-        }
-
-        /**
-         * Returns a new Vector3 set with the mesh pivot point World coordinates.  
-         */
-        public getAbsolutePivotPoint(): Vector3 {
-            var point = Vector3.Zero();
-            this.getAbsolutePivotPointToRef(point);
-            return point;
-        }
-
-        /**
-         * Defines the passed mesh as the parent of the current mesh.  
-         * Returns the AbstractMesh.  
-         */
-        public setParent(mesh: Nullable<AbstractMesh>): AbstractMesh {
-            var parent = (<AbstractMesh>mesh);
-
-            if (mesh == null) {
-
-                var rotation = Tmp.Quaternion[0];
-                var position = Tmp.Vector3[0];
-                var scale = Tmp.Vector3[1];
-
-                this.getWorldMatrix().decompose(scale, rotation, position);
-
-                if (this.rotationQuaternion) {
-                    this.rotationQuaternion.copyFrom(rotation);
-                } else {
-                    rotation.toEulerAnglesToRef(this.rotation);
-                }
-
-                this.position.x = position.x;
-                this.position.y = position.y;
-                this.position.z = position.z;
-
-            } else {
-
-                var position = Tmp.Vector3[0];
-                var m1 = Tmp.Matrix[0];
-
-                parent.getWorldMatrix().invertToRef(m1);
-                Vector3.TransformCoordinatesToRef(this.position, m1, position);
-
-                this.position.copyFrom(position);
-            }
-            this.parent = parent;
-            return this;
-        }
+        } 
 
         /**
          * Adds the passed mesh as a child to the current mesh.  
@@ -2188,19 +1654,6 @@
             return this;
         }
 
-        /**
-         * Sets the Vector3 "result" coordinates with the mesh pivot point World coordinates.  
-         * Returns the AbstractMesh.  
-         */
-        public getAbsolutePivotPointToRef(result: Vector3): AbstractMesh {
-            result.x = this._pivotMatrix.m[12];
-            result.y = this._pivotMatrix.m[13];
-            result.z = this._pivotMatrix.m[14];
-            this.getPivotPointToRef(result);
-            Vector3.TransformCoordinatesToRef(result, this.getWorldMatrix(), result);
-            return this;
-        }
-
         // Facet data
         /** 
          *  Initialize the facet data arrays : facetNormals, facetPositions and facetPartitioning.   

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

@@ -912,6 +912,7 @@
         /**
          * Sets the mesh indices.  
          * Expects an array populated with integers or a typed array (Int32Array, Uint32Array, Uint16Array).
+         * Type is Uint16Array by default unless the mesh has more than 65536 vertices.
          * If the mesh has no geometry, a new Geometry object is created and set to the mesh. 
          * This method creates a new index buffer each call.  
          * Returns the Mesh.  

+ 602 - 0
src/Mesh/babylon.transformNode.ts

@@ -0,0 +1,602 @@
+module BABYLON {
+    export class TransformNode extends Node {
+        // Statics
+        public static BILLBOARDMODE_NONE = 0;
+        public static BILLBOARDMODE_X = 1;
+        public static BILLBOARDMODE_Y = 2;
+        public static BILLBOARDMODE_Z = 4;
+        public static BILLBOARDMODE_ALL = 7;
+        
+        // Properties
+        private _rotation = Vector3.Zero();
+        private _rotationQuaternion: Nullable<Quaternion>;
+        protected _scaling = Vector3.One();
+        protected _isDirty = false;
+        private _transformToBoneReferal: Nullable<TransformNode>;
+        
+        public billboardMode = AbstractMesh.BILLBOARDMODE_NONE;
+        public scalingDeterminant = 1;
+        public infiniteDistance = false;
+        public position = Vector3.Zero();
+                        
+        // Cache        
+        public _poseMatrix: Matrix;
+        private _localWorld = Matrix.Zero();
+        public _worldMatrix = Matrix.Zero();
+        private _absolutePosition = Vector3.Zero();
+        private _pivotMatrix = Matrix.Identity();
+        private _pivotMatrixInverse: Matrix;
+        private _postMultiplyPivotMatrix = false;        
+        
+        protected _isWorldMatrixFrozen = false;
+
+        /**
+        * An event triggered after the world matrix is updated
+        * @type {BABYLON.Observable}
+        */
+        public onAfterWorldMatrixUpdateObservable = new Observable<TransformNode>();        
+                
+       /**
+         * Rotation property : a Vector3 depicting the rotation value in radians around each local axis X, Y, Z. 
+         * If rotation quaternion is set, this Vector3 will (almost always) be the Zero vector!
+         * Default : (0.0, 0.0, 0.0)
+         */
+        public get rotation(): Vector3 {
+            return this._rotation;
+        }
+
+        public set rotation(newRotation: Vector3) {
+            this._rotation = newRotation;
+        }
+
+        /**
+         * Scaling property : a Vector3 depicting the mesh scaling along each local axis X, Y, Z.  
+         * Default : (1.0, 1.0, 1.0)
+         */
+        public get scaling(): Vector3 {
+            return this._scaling;
+        }
+
+        /**
+         * Scaling property : a Vector3 depicting the mesh scaling along each local axis X, Y, Z.  
+         * Default : (1.0, 1.0, 1.0)
+        */
+        public set scaling(newScaling: Vector3) {
+            this._scaling = newScaling;
+        }
+
+        /**
+         * Rotation Quaternion property : this a Quaternion object depicting the mesh rotation by using a unit quaternion. 
+         * It's null by default.  
+         * If set, only the rotationQuaternion is then used to compute the mesh rotation and its property `.rotation\ is then ignored and set to (0.0, 0.0, 0.0)
+         */
+        public get rotationQuaternion(): Nullable<Quaternion> {
+            return this._rotationQuaternion;
+        }
+
+        public set rotationQuaternion(quaternion: Nullable<Quaternion>) {
+            this._rotationQuaternion = quaternion;
+            //reset the rotation vector. 
+            if (quaternion && this.rotation.length()) {
+                this.rotation.copyFromFloats(0.0, 0.0, 0.0);
+            }
+        }
+
+        /**
+         * Returns the latest update of the World matrix
+         * Returns a Matrix.  
+         */
+        public getWorldMatrix(): Matrix {
+            if (this._currentRenderId !== this.getScene().getRenderId()) {
+                this.computeWorldMatrix();
+            }
+            return this._worldMatrix;
+        }
+
+        /**
+         * Returns directly the latest state of the mesh World matrix. 
+         * A Matrix is returned.    
+         */
+        public get worldMatrixFromCache(): Matrix {
+            return this._worldMatrix;
+        }
+
+        /**
+         * Returns the current mesh absolute position.
+         * Retuns a Vector3.
+         */
+        public get absolutePosition(): Vector3 {
+            return this._absolutePosition;
+        }
+
+        /**
+         * Sets a new pivot matrix to the mesh.  
+         * Returns the AbstractMesh.
+        */
+        public setPivotMatrix(matrix: Matrix, postMultiplyPivotMatrix = false): TransformNode {
+            this._pivotMatrix = matrix.clone();
+            this._cache.pivotMatrixUpdated = true;
+            this._postMultiplyPivotMatrix = postMultiplyPivotMatrix;
+
+            if (this._postMultiplyPivotMatrix) {
+                this._pivotMatrixInverse = Matrix.Invert(matrix);
+            }
+            return this;
+        }
+
+        /**
+         * Returns the mesh pivot matrix.
+         * Default : Identity.  
+         * A Matrix is returned.  
+         */
+        public getPivotMatrix(): Matrix {
+            return this._pivotMatrix;
+        }
+
+        /**
+         * Prevents the World matrix to be computed any longer.
+         * Returns the AbstractMesh.  
+         */
+        public freezeWorldMatrix(): TransformNode {
+            this._isWorldMatrixFrozen = false;  // no guarantee world is not already frozen, switch off temporarily
+            this.computeWorldMatrix(true);
+            this._isWorldMatrixFrozen = true;
+            return this;
+        }
+
+        /**
+         * Allows back the World matrix computation. 
+         * Returns the AbstractMesh.  
+         */
+        public unfreezeWorldMatrix() {
+            this._isWorldMatrixFrozen = false;
+            this.computeWorldMatrix(true);
+            return this;
+        }
+
+        /**
+         * True if the World matrix has been frozen.  
+         * Returns a boolean.  
+         */
+        public get isWorldMatrixFrozen(): boolean {
+            return this._isWorldMatrixFrozen;
+        }
+
+     /**
+         * Retuns the mesh absolute position in the World.  
+         * Returns a Vector3.
+         */
+        public getAbsolutePosition(): Vector3 {
+            this.computeWorldMatrix();
+            return this._absolutePosition;
+        }
+
+        /**
+         * Sets the mesh absolute position in the World from a Vector3 or an Array(3).
+         * Returns the AbstractMesh.  
+         */
+        public setAbsolutePosition(absolutePosition: Vector3): TransformNode {
+            if (!absolutePosition) {
+                return this;
+            }
+            var absolutePositionX;
+            var absolutePositionY;
+            var absolutePositionZ;
+            if (absolutePosition.x === undefined) {
+                if (arguments.length < 3) {
+                    return this;
+                }
+                absolutePositionX = arguments[0];
+                absolutePositionY = arguments[1];
+                absolutePositionZ = arguments[2];
+            }
+            else {
+                absolutePositionX = absolutePosition.x;
+                absolutePositionY = absolutePosition.y;
+                absolutePositionZ = absolutePosition.z;
+            }
+            if (this.parent) {
+                var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
+                invertParentWorldMatrix.invert();
+                var worldPosition = new Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
+                this.position = Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
+            } else {
+                this.position.x = absolutePositionX;
+                this.position.y = absolutePositionY;
+                this.position.z = absolutePositionZ;
+            }
+            return this;
+        }   
+
+      /**
+         * Sets the mesh position in its local space.  
+         * Returns the AbstractMesh.  
+         */
+        public setPositionWithLocalVector(vector3: Vector3): TransformNode {
+            this.computeWorldMatrix();
+            this.position = Vector3.TransformNormal(vector3, this._localWorld);
+            return this;
+        }
+
+        /**
+         * Returns the mesh position in the local space from the current World matrix values.
+         * Returns a new Vector3.
+         */
+        public getPositionExpressedInLocalSpace(): Vector3 {
+            this.computeWorldMatrix();
+            var invLocalWorldMatrix = this._localWorld.clone();
+            invLocalWorldMatrix.invert();
+
+            return Vector3.TransformNormal(this.position, invLocalWorldMatrix);
+        }
+
+        /**
+         * Translates the mesh along the passed Vector3 in its local space.  
+         * Returns the AbstractMesh. 
+         */
+        public locallyTranslate(vector3: Vector3): TransformNode {
+            this.computeWorldMatrix(true);
+            this.position = Vector3.TransformCoordinates(vector3, this._localWorld);
+            return this;
+        }
+
+        private static _lookAtVectorCache = new Vector3(0, 0, 0);
+        public lookAt(targetPoint: Vector3, yawCor: number = 0, pitchCor: number = 0, rollCor: number = 0, space: Space = Space.LOCAL): TransformNode {
+            /// <summary>Orients a mesh towards a target point. Mesh must be drawn facing user.</summary>
+            /// <param name="targetPoint" type="Vector3">The position (must be in same space as current mesh) to look at</param>
+            /// <param name="yawCor" type="Number">optional yaw (y-axis) correction in radians</param>
+            /// <param name="pitchCor" type="Number">optional pitch (x-axis) correction in radians</param>
+            /// <param name="rollCor" type="Number">optional roll (z-axis) correction in radians</param>
+            /// <returns>Mesh oriented towards targetMesh</returns>
+
+            var dv = AbstractMesh._lookAtVectorCache;
+            var pos = space === Space.LOCAL ? this.position : this.getAbsolutePosition();
+            targetPoint.subtractToRef(pos, dv);
+            var yaw = -Math.atan2(dv.z, dv.x) - Math.PI / 2;
+            var len = Math.sqrt(dv.x * dv.x + dv.z * dv.z);
+            var pitch = Math.atan2(dv.y, len);
+            this.rotationQuaternion = this.rotationQuaternion || new Quaternion();
+            Quaternion.RotationYawPitchRollToRef(yaw + yawCor, pitch + pitchCor, rollCor, this.rotationQuaternion);
+            return this;
+        }        
+
+       /**
+         * Returns a new Vector3 what is the localAxis, expressed in the mesh local space, rotated like the mesh.  
+         * This Vector3 is expressed in the World space.  
+         */
+        public getDirection(localAxis: Vector3): Vector3 {
+            var result = Vector3.Zero();
+
+            this.getDirectionToRef(localAxis, result);
+
+            return result;
+        }
+
+        /**
+         * Sets the Vector3 "result" as the rotated Vector3 "localAxis" in the same rotation than the mesh.
+         * localAxis is expressed in the mesh local space.
+         * result is computed in the Wordl space from the mesh World matrix.  
+         * Returns the AbstractMesh.  
+         */
+        public getDirectionToRef(localAxis: Vector3, result: Vector3): TransformNode {
+            Vector3.TransformNormalToRef(localAxis, this.getWorldMatrix(), result);
+            return this;
+        }
+
+        public setPivotPoint(point: Vector3, space: Space = Space.LOCAL): TransformNode {
+            if (this.getScene().getRenderId() == 0) {
+                this.computeWorldMatrix(true);
+            }
+
+            var wm = this.getWorldMatrix();
+
+            if (space == Space.WORLD) {
+                var tmat = Tmp.Matrix[0];
+                wm.invertToRef(tmat);
+                point = Vector3.TransformCoordinates(point, tmat);
+            }
+
+            Vector3.TransformCoordinatesToRef(point, wm, this.position);
+            this._pivotMatrix.m[12] = -point.x;
+            this._pivotMatrix.m[13] = -point.y;
+            this._pivotMatrix.m[14] = -point.z;
+            this._cache.pivotMatrixUpdated = true;
+            return this;
+        }
+
+        /**
+         * Returns a new Vector3 set with the mesh pivot point coordinates in the local space.  
+         */
+        public getPivotPoint(): Vector3 {
+            var point = Vector3.Zero();
+            this.getPivotPointToRef(point);
+            return point;
+        }
+
+        /**
+         * Sets the passed Vector3 "result" with the coordinates of the mesh pivot point in the local space.   
+         * Returns the AbstractMesh.   
+         */
+        public getPivotPointToRef(result: Vector3): TransformNode {
+            result.x = -this._pivotMatrix.m[12];
+            result.y = -this._pivotMatrix.m[13];
+            result.z = -this._pivotMatrix.m[14];
+            return this;
+        }
+
+        /**
+         * Returns a new Vector3 set with the mesh pivot point World coordinates.  
+         */
+        public getAbsolutePivotPoint(): Vector3 {
+            var point = Vector3.Zero();
+            this.getAbsolutePivotPointToRef(point);
+            return point;
+        }
+
+        /**
+         * Sets the Vector3 "result" coordinates with the mesh pivot point World coordinates.  
+         * Returns the AbstractMesh.  
+         */
+        public getAbsolutePivotPointToRef(result: Vector3): TransformNode {
+            result.x = this._pivotMatrix.m[12];
+            result.y = this._pivotMatrix.m[13];
+            result.z = this._pivotMatrix.m[14];
+            this.getPivotPointToRef(result);
+            Vector3.TransformCoordinatesToRef(result, this.getWorldMatrix(), result);
+            return this;
+        }        
+
+        /**
+         * Defines the passed mesh as the parent of the current mesh.  
+         * Returns the AbstractMesh.  
+         */
+        public setParent(mesh: Nullable<AbstractMesh>): TransformNode {
+            var parent = (<AbstractMesh>mesh);
+
+            if (mesh == null) {
+
+                var rotation = Tmp.Quaternion[0];
+                var position = Tmp.Vector3[0];
+                var scale = Tmp.Vector3[1];
+
+                this.getWorldMatrix().decompose(scale, rotation, position);
+
+                if (this.rotationQuaternion) {
+                    this.rotationQuaternion.copyFrom(rotation);
+                } else {
+                    rotation.toEulerAnglesToRef(this.rotation);
+                }
+
+                this.position.x = position.x;
+                this.position.y = position.y;
+                this.position.z = position.z;
+
+            } else {
+
+                var position = Tmp.Vector3[0];
+                var m1 = Tmp.Matrix[0];
+
+                parent.getWorldMatrix().invertToRef(m1);
+                Vector3.TransformCoordinatesToRef(this.position, m1, position);
+
+                this.position.copyFrom(position);
+            }
+            this.parent = parent;
+            return this;
+        }       
+        
+        private _nonUniformScaling = false;
+        public get nonUniformScaling(): boolean {
+            return this._nonUniformScaling;
+        }
+
+        public _updateNonUniformScalingState(value: boolean): boolean {
+            if (this._nonUniformScaling === value) {
+                return false;
+            }
+
+            this._nonUniformScaling = true;
+            return true;
+        }        
+
+        /**
+         * Attach the current TransformNode to another TransformNode associated with a bone
+         * @param bone Bone affecting the TransformNode
+         * @param affectedTransformNode TransformNode associated with the bone 
+         */
+        public attachToBone(bone: Bone, affectedTransformNode: TransformNode): TransformNode {
+            this._transformToBoneReferal = affectedTransformNode;
+            this.parent = bone;
+
+            if (bone.getWorldMatrix().determinant() < 0) {
+                this.scalingDeterminant *= -1;
+            }
+            return this;
+        }
+
+        public detachFromBone(): TransformNode {
+            if (!this.parent) {
+                return this;
+            }
+
+            if (this.parent.getWorldMatrix().determinant() < 0) {
+                this.scalingDeterminant *= -1;
+            }
+            this._transformToBoneReferal = null;
+            this.parent = null;
+            return this;
+        }        
+        
+        /**
+         * Computes the mesh World matrix and returns it.  
+         * If the mesh world matrix is frozen, this computation does nothing more than returning the last frozen values.  
+         * If the parameter `force` is let to `false` (default), the current cached World matrix is returned. 
+         * If the parameter `force`is set to `true`, the actual computation is done.  
+         * Returns the mesh World Matrix.
+         */
+        public computeWorldMatrix(force?: boolean): Matrix {
+            if (this._isWorldMatrixFrozen) {
+                return this._worldMatrix;
+            }
+
+            if (!force && this.isSynchronized(true)) {
+                return this._worldMatrix;
+            }
+
+            this._cache.position.copyFrom(this.position);
+            this._cache.scaling.copyFrom(this.scaling);
+            this._cache.pivotMatrixUpdated = false;
+            this._cache.billboardMode = this.billboardMode;
+            this._currentRenderId = this.getScene().getRenderId();
+            this._isDirty = false;
+
+            // Scaling
+            Matrix.ScalingToRef(this.scaling.x * this.scalingDeterminant, this.scaling.y * this.scalingDeterminant, this.scaling.z * this.scalingDeterminant, Tmp.Matrix[1]);
+
+            // Rotation
+
+            //rotate, if quaternion is set and rotation was used
+            if (this.rotationQuaternion) {
+                var len = this.rotation.length();
+                if (len) {
+                    this.rotationQuaternion.multiplyInPlace(BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z))
+                    this.rotation.copyFromFloats(0, 0, 0);
+                }
+            }
+
+            if (this.rotationQuaternion) {
+                this.rotationQuaternion.toRotationMatrix(Tmp.Matrix[0]);
+                this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
+            } else {
+                Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, Tmp.Matrix[0]);
+                this._cache.rotation.copyFrom(this.rotation);
+            }
+
+            // Translation
+            let camera = (<Camera>this.getScene().activeCamera);
+            
+            if (this.infiniteDistance && !this.parent && camera) {
+
+                var cameraWorldMatrix = camera.getWorldMatrix();
+
+                var cameraGlobalPosition = new Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
+
+                Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y,
+                    this.position.z + cameraGlobalPosition.z, Tmp.Matrix[2]);
+            } else {
+                Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, Tmp.Matrix[2]);
+            }
+
+            // Composing transformations
+            this._pivotMatrix.multiplyToRef(Tmp.Matrix[1], Tmp.Matrix[4]);
+            Tmp.Matrix[4].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[5]);
+
+            // Billboarding (testing PG:http://www.babylonjs-playground.com/#UJEIL#13)
+            if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE && camera) {
+                if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_ALL) !== AbstractMesh.BILLBOARDMODE_ALL) {
+                    // Need to decompose each rotation here
+                    var currentPosition = Tmp.Vector3[3];
+
+                    if (this.parent && this.parent.getWorldMatrix) {
+                        if (this._transformToBoneReferal) {
+                            this.parent.getWorldMatrix().multiplyToRef(this._transformToBoneReferal.getWorldMatrix(), Tmp.Matrix[6]);
+                            Vector3.TransformCoordinatesToRef(this.position, Tmp.Matrix[6], currentPosition);
+                        } else {
+                            Vector3.TransformCoordinatesToRef(this.position, this.parent.getWorldMatrix(), currentPosition);
+                        }
+                    } else {
+                        currentPosition.copyFrom(this.position);
+                    }
+
+                    currentPosition.subtractInPlace(camera.globalPosition);
+
+                    var finalEuler = Tmp.Vector3[4].copyFromFloats(0, 0, 0);
+                    if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_X) === AbstractMesh.BILLBOARDMODE_X) {
+                        finalEuler.x = Math.atan2(-currentPosition.y, currentPosition.z);
+                    }
+
+                    if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_Y) === AbstractMesh.BILLBOARDMODE_Y) {
+                        finalEuler.y = Math.atan2(currentPosition.x, currentPosition.z);
+                    }
+
+                    if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_Z) === AbstractMesh.BILLBOARDMODE_Z) {
+                        finalEuler.z = Math.atan2(currentPosition.y, currentPosition.x);
+                    }
+
+                    Matrix.RotationYawPitchRollToRef(finalEuler.y, finalEuler.x, finalEuler.z, Tmp.Matrix[0]);
+                } else {
+                    Tmp.Matrix[1].copyFrom(camera.getViewMatrix());
+
+                    Tmp.Matrix[1].setTranslationFromFloats(0, 0, 0);
+                    Tmp.Matrix[1].invertToRef(Tmp.Matrix[0]);
+                }
+
+                Tmp.Matrix[1].copyFrom(Tmp.Matrix[5]);
+                Tmp.Matrix[1].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[5]);
+            }
+
+            // Local world
+            Tmp.Matrix[5].multiplyToRef(Tmp.Matrix[2], this._localWorld);
+
+            // Parent
+            if (this.parent && this.parent.getWorldMatrix) {
+                if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE) {
+                    if (this._transformToBoneReferal) {
+                        this.parent.getWorldMatrix().multiplyToRef(this._transformToBoneReferal.getWorldMatrix(), Tmp.Matrix[6]);
+                        Tmp.Matrix[5].copyFrom(Tmp.Matrix[6]);
+                    } else {
+                        Tmp.Matrix[5].copyFrom(this.parent.getWorldMatrix());
+                    }
+
+                    this._localWorld.getTranslationToRef(Tmp.Vector3[5]);
+                    Vector3.TransformCoordinatesToRef(Tmp.Vector3[5], Tmp.Matrix[5], Tmp.Vector3[5]);
+                    this._worldMatrix.copyFrom(this._localWorld);
+                    this._worldMatrix.setTranslation(Tmp.Vector3[5]);
+
+                } else {
+                    if (this._transformToBoneReferal) {
+                        this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), Tmp.Matrix[6]);
+                        Tmp.Matrix[6].multiplyToRef(this._transformToBoneReferal.getWorldMatrix(), this._worldMatrix);
+                    } else {
+                        this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
+                    }
+                }
+                this._markSyncedWithParent();
+            } else {
+                this._worldMatrix.copyFrom(this._localWorld);
+            }
+
+            // Post multiply inverse of pivotMatrix
+            if (this._postMultiplyPivotMatrix) {
+                this._worldMatrix.multiplyToRef(this._pivotMatrixInverse, this._worldMatrix);
+            }
+
+            // Normal matrix
+            if (this.scaling.isNonUniform) {
+                this._updateNonUniformScalingState(true);
+            } else if (this.parent && (<TransformNode>this.parent)._nonUniformScaling) {
+                this._updateNonUniformScalingState((<TransformNode>this.parent)._nonUniformScaling);
+            } else {
+                this._updateNonUniformScalingState(false);
+            }
+
+            this._afterComputeWorldMatrix();
+
+            // Absolute position
+            this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
+
+            // Callbacks
+            this.onAfterWorldMatrixUpdateObservable.notifyObservers(this);
+
+            if (!this._poseMatrix) {
+                this._poseMatrix = Matrix.Invert(this._worldMatrix);
+            }
+
+            return this._worldMatrix;
+        }   
+
+        protected _afterComputeWorldMatrix(): void {
+
+        }
+    }
+}

+ 3 - 3
src/Physics/babylon.physicsImpostor.ts

@@ -24,9 +24,9 @@ module BABYLON {
         getScene?(): Scene;
         getAbsolutePosition(): Vector3;
         getAbsolutePivotPoint(): Vector3;
-        rotate(axis: Vector3, amount: number, space?: Space): IPhysicsEnabledObject;
-        translate(axis: Vector3, distance: number, space?: Space): IPhysicsEnabledObject;
-        setAbsolutePosition(absolutePosition: Vector3): IPhysicsEnabledObject;
+        rotate(axis: Vector3, amount: number, space?: Space): TransformNode;
+        translate(axis: Vector3, distance: number, space?: Space): TransformNode;
+        setAbsolutePosition(absolutePosition: Vector3): TransformNode;
     }
 
     export class PhysicsImpostor {

+ 5 - 4
tests/nullEngine/app.js

@@ -133,9 +133,10 @@ BABYLON.SceneLoader.Load("https://playground.babylonjs.com/scenes/", "skull.baby
     console.log('scene loaded!');
     for (var index = 0; index < scene.meshes.length; index++) {
         console.log(scene.meshes[index].name);
-    }    
-    engine.runRenderLoop(function() {
-        scene.render();
-    });
+    } 
+    engine.dispose();   
+   // engine.runRenderLoop(function() {
+     //   scene.render();
+    //});
   
   }, progress => {}, (scene, err) => console.error('error:', err));