Przeglądaj źródła

Merge pull request #3 from BabylonJS/master

Getting changes from main repo
Etienne Margraff 9 lat temu
rodzic
commit
a58361e6e4
100 zmienionych plików z 54983 dodań i 12933 usunięć
  1. 1 0
      .gitattributes
  2. 3 0
      .gitignore
  3. 1 1
      Exporters/Unity 5/Unity3D2Babylon/ExporterWindow.cs
  4. 103 20
      Exporters/Unity 5/Unity3D2Babylon/SceneBuilder.Meshes.cs
  5. 69 9
      Exporters/Unity 5/Unity3D2Babylon/SceneBuilder.cs
  6. 1 2
      Tools/Gulp/config.json
  7. 20 19
      dist/preview release/babylon.core.js
  8. 1290 1198
      dist/preview release/babylon.d.ts
  9. 27 27
      dist/preview release/babylon.js
  10. 2139 1924
      dist/preview release/babylon.max.js
  11. 26 26
      dist/preview release/babylon.noworker.js
  12. 86 83
      dist/preview release/what's new.md
  13. 41 42
      loaders/glTF/README.md
  14. 1306 1166
      loaders/glTF/babylon.glTFFileLoader.js
  15. 1533 1388
      loaders/glTF/babylon.glTFFileLoader.ts
  16. 263 279
      loaders/glTF/babylon.glTFFileLoaderInterfaces.ts
  17. 73 64
      materialsLibrary/config.json
  18. 43 2
      materialsLibrary/dist/babylon.fireMaterial.js
  19. 1 1
      materialsLibrary/dist/babylon.fireMaterial.min.js
  20. 499 0
      materialsLibrary/dist/babylon.furMaterial.js
  21. 1 0
      materialsLibrary/dist/babylon.furMaterial.min.js
  22. 61 10
      materialsLibrary/dist/babylon.lavaMaterial.js
  23. 1 1
      materialsLibrary/dist/babylon.lavaMaterial.min.js
  24. 29 2
      materialsLibrary/dist/babylon.normalMaterial.js
  25. 1 1
      materialsLibrary/dist/babylon.normalMaterial.min.js
  26. 140 4
      materialsLibrary/dist/babylon.pbrMaterial.js
  27. 3 3
      materialsLibrary/dist/babylon.pbrMaterial.min.js
  28. 29 2
      materialsLibrary/dist/babylon.simpleMaterial.js
  29. 1 1
      materialsLibrary/dist/babylon.simpleMaterial.min.js
  30. 66 2
      materialsLibrary/dist/babylon.terrainMaterial.js
  31. 1 1
      materialsLibrary/dist/babylon.terrainMaterial.min.js
  32. 51 2
      materialsLibrary/dist/babylon.waterMaterial.js
  33. 1 1
      materialsLibrary/dist/babylon.waterMaterial.min.js
  34. 29 0
      materialsLibrary/dist/dts/babylon.fireMaterial.d.ts
  35. 30 0
      materialsLibrary/dist/dts/babylon.furMaterial.d.ts
  36. 33 0
      materialsLibrary/dist/dts/babylon.lavaMaterial.d.ts
  37. 26 0
      materialsLibrary/dist/dts/babylon.normalMaterial.d.ts
  38. 85 0
      materialsLibrary/dist/dts/babylon.pbrMaterial.d.ts
  39. 26 0
      materialsLibrary/dist/dts/babylon.simpleMaterial.d.ts
  40. 35 0
      materialsLibrary/dist/dts/babylon.terrainMaterial.d.ts
  41. 77 0
      materialsLibrary/dist/dts/babylon.waterMaterial.d.ts
  42. 70 66
      materialsLibrary/gulpfile.js
  43. 414 357
      materialsLibrary/materials/fire/babylon.fireMaterial.ts
  44. 601 0
      materialsLibrary/materials/fur/babylon.furMaterial.ts
  45. 565 0
      materialsLibrary/materials/fur/fur.fragment.fx
  46. 202 0
      materialsLibrary/materials/fur/fur.vertex.fx
  47. 236 0
      materialsLibrary/materials/fur/readme.md
  48. 80 15
      materialsLibrary/materials/lava/babylon.lavaMaterial.ts
  49. 5 4
      materialsLibrary/materials/lava/lava.fragment.fx
  50. 38 19
      materialsLibrary/materials/lava/lava.vertex.fx
  51. 555 516
      materialsLibrary/materials/normal/babylon.normalMaterial.ts
  52. 163 0
      materialsLibrary/materials/pbr/babylon.pbrMaterial.ts
  53. 554 516
      materialsLibrary/materials/simple/babylon.simpleMaterial.ts
  54. 664 577
      materialsLibrary/materials/terrain/babylon.terrainMaterial.ts
  55. 64 1
      materialsLibrary/materials/water/babylon.waterMaterial.ts
  56. 209 209
      materialsLibrary/materials/water/water.vertex.fx
  57. 14 0
      materialsLibrary/test/add/addfire.js
  58. 54 0
      materialsLibrary/test/add/addfur.js
  59. 19 0
      materialsLibrary/test/add/addterrain.js
  60. 36966 0
      materialsLibrary/test/babylon.max.js
  61. 25 31
      materialsLibrary/test/index.html
  62. 20 0
      materialsLibrary/test/index.js
  63. BIN
      materialsLibrary/test/textures/heightMap.png
  64. BIN
      materialsLibrary/test/textures/leopard_fur.JPG
  65. BIN
      materialsLibrary/test/textures/mixMap.png
  66. BIN
      materialsLibrary/test/textures/speckles.jpg
  67. 21 34
      proceduralTexturesLibrary/test/index.html
  68. 20 20
      proceduralTexturesLibrary/test/index.js
  69. 1 91
      readme.md
  70. 88 88
      src/Actions/babylon.action.ts
  71. 151 0
      src/Actions/babylon.actionManager.js
  72. 460 280
      src/Actions/babylon.actionManager.ts
  73. 115 115
      src/Actions/babylon.condition.ts
  74. 207 207
      src/Actions/babylon.directActions.ts
  75. 56 56
      src/Actions/babylon.interpolateValueAction.ts
  76. 130 130
      src/Animations/babylon.animatable.ts
  77. 67 0
      src/Animations/babylon.animation.js
  78. 601 520
      src/Animations/babylon.animation.ts
  79. 188 188
      src/Animations/babylon.easing.ts
  80. 127 127
      src/Audio/babylon.analyser.ts
  81. 84 84
      src/Audio/babylon.audioEngine.ts
  82. 32 0
      src/Audio/babylon.sound.js
  83. 518 481
      src/Audio/babylon.sound.ts
  84. 113 113
      src/Audio/babylon.soundtrack.ts
  85. 91 91
      src/Bones/babylon.bone.ts
  86. 34 0
      src/Bones/babylon.skeleton.js
  87. 186 139
      src/Bones/babylon.skeleton.ts
  88. 49 49
      src/Cameras/VR/babylon.vrDeviceOrientationCamera.ts
  89. 80 80
      src/Cameras/VR/babylon.webVRCamera.ts
  90. 36 36
      src/Cameras/babylon.anaglyphCamera.js
  91. 15 1
      src/Cameras/babylon.arcRotateCamera.js
  92. 672 654
      src/Cameras/babylon.arcRotateCamera.ts
  93. 129 0
      src/Cameras/babylon.camera.js
  94. 738 589
      src/Cameras/babylon.camera.ts
  95. 1 1
      src/Cameras/babylon.deviceOrientationCamera.js
  96. 77 77
      src/Cameras/babylon.deviceOrientationCamera.ts
  97. 12 0
      src/Cameras/babylon.followCamera.js
  98. 107 89
      src/Cameras/babylon.followCamera.ts
  99. 8 1
      src/Cameras/babylon.freeCamera.js
  100. 0 0
      src/Cameras/babylon.freeCamera.ts

+ 1 - 0
.gitattributes

@@ -0,0 +1 @@
+* -crlf

+ 3 - 0
.gitignore

@@ -120,3 +120,6 @@ UpgradeLog*.XML
 # Do not ignore loaders/obj
 !loaders/*
 node_modules
+
+# for JetBrains IDE
+.idea

+ 1 - 1
Exporters/Unity 5/Unity3D2Babylon/ExporterWindow.cs

@@ -40,7 +40,7 @@ namespace Unity3D2Babylon
 
         void Initialize()
         {
-            title = "Babylon.js";
+            titleContent.text = "Babylon.js";
         }
 
         void OnGUI()

+ 103 - 20
Exporters/Unity 5/Unity3D2Babylon/SceneBuilder.Meshes.cs

@@ -6,22 +6,113 @@ namespace Unity3D2Babylon
 {
     partial class SceneBuilder
     {
-        private void ConvertUnityEmptyObjectToBabylon(GameObject gameObject)
+        private BabylonAbstractMesh ConvertUnityMeshToInstance(GameObject gameObject)
         {
-            BabylonMesh babylonMesh = new BabylonMesh { name = gameObject.name, id = GetID(gameObject) };
+            BabylonAbstractMesh babylonMesh = new BabylonAbstractMesh();
 
-            var transform = gameObject.transform;
+            Transform transform = gameObject.transform;
+            babylonMesh.name = gameObject.name;
+            babylonMesh.position = new float[3];
+            babylonMesh.position[0] = transform.position.x;
+            babylonMesh.position[1] = transform.position.y;
+            babylonMesh.position[2] = transform.position.z;
 
-            babylonMesh.parentId = GetParentID(transform);
+            babylonMesh.rotation = new float[3];
+            babylonMesh.rotation[0] = transform.rotation.eulerAngles.x * (float)Math.PI / 180;
+            babylonMesh.rotation[1] = transform.rotation.eulerAngles.y * (float)Math.PI / 180;
+            babylonMesh.rotation[2] = transform.rotation.eulerAngles.z * (float)Math.PI / 180;
+
+            babylonMesh.scaling = new float[3];
+            babylonMesh.scaling[0] = transform.localScale.x;
+            babylonMesh.scaling[1] = transform.localScale.y;
+            babylonMesh.scaling[2] = transform.localScale.z;
+            return babylonMesh;
+        }
 
-            babylonMesh.position = transform.localPosition.ToFloat();
+        private void ConvertTransform(BabylonMesh babylonMesh, Transform transform, GameObject gameObject, BabylonAbstractMesh[] instances = null)
+        {
+            Action SetTransformFromGameobject = () =>
+            {
+                babylonMesh.position = transform.localPosition.ToFloat();
 
-            babylonMesh.rotation = new float[3];
-            babylonMesh.rotation[0] = transform.localRotation.eulerAngles.x * (float)Math.PI / 180;
-            babylonMesh.rotation[1] = transform.localRotation.eulerAngles.y * (float)Math.PI / 180;
-            babylonMesh.rotation[2] = transform.localRotation.eulerAngles.z * (float)Math.PI / 180;
+                babylonMesh.rotation = new float[3];
+                babylonMesh.rotation[0] = transform.localRotation.eulerAngles.x * (float)Math.PI / 180;
+                babylonMesh.rotation[1] = transform.localRotation.eulerAngles.y * (float)Math.PI / 180;
+                babylonMesh.rotation[2] = transform.localRotation.eulerAngles.z * (float)Math.PI / 180;
+
+                babylonMesh.scaling = transform.localScale.ToFloat();
+            };
 
-            babylonMesh.scaling = transform.localScale.ToFloat();
+            Action SetTransformFromFirstInstance = () =>
+            {
+                BabylonAbstractMesh first = instances[0];
+
+                babylonMesh.position = new float[3];
+                babylonMesh.position[0] = first.position[0];
+                babylonMesh.position[1] = first.position[1];
+                babylonMesh.position[2] = first.position[2];
+
+                babylonMesh.rotation = new float[3];
+                babylonMesh.rotation[0] = first.rotation[0];
+                babylonMesh.rotation[1] = first.rotation[1];
+                babylonMesh.rotation[2] = first.rotation[2];
+
+                babylonMesh.scaling = new float[3];
+                babylonMesh.scaling[0] = first.scaling[0];
+                babylonMesh.scaling[1] = first.scaling[1];
+                babylonMesh.scaling[2] = first.scaling[2];
+            };
+
+            //Check if this is a prefab
+            if (instances != null)
+            {
+                /*
+                    Unity3D prefabs don't have transforms (position, rotation, scale) because they are just a template and are not drawn on screen          
+                    but Babylon.js meshes must have a transform because they are drawn on the screen
+                    so what we do is take the first instance
+                    copy its transform (position, rotation, scale) into the prefab mesh
+                    then remove that first instance
+                */
+
+                babylonMesh.instances = new BabylonAbstractMesh[instances.Length - 1];
+
+                //Effectively remove first instance from list of all instances
+                for (int i = 0; i < instances.Length - 1; i++)
+                {
+                    babylonMesh.instances[i] = instances[i + 1];
+                }
+
+                //If this is the root object then copy values directly from first instance
+                if (GetParentID(transform) == null)
+                {
+                    SetTransformFromFirstInstance();
+                }
+                else
+                {
+                    GameObject parent = gameObject.transform.parent.gameObject;
+                    if ((parent.GetComponent<Light>() == null) && (parent.GetComponent<Camera>() == null))
+                    {
+                        SetTransformFromGameobject();
+                    } else
+                    {
+                        SetTransformFromFirstInstance();
+                    }
+                }
+            }
+            else
+            {
+                SetTransformFromGameobject();
+            }
+        }
+
+        private void ConvertUnityEmptyObjectToBabylon(GameObject gameObject, BabylonAbstractMesh[] instances = null)
+        {
+            BabylonMesh babylonMesh = new BabylonMesh { name = gameObject.name, id = GetID(gameObject) };
+
+            var transform = gameObject.transform;
+
+            babylonMesh.parentId = GetParentID(transform);
+            ConvertTransform(babylonMesh, transform, gameObject, instances);
 
             babylonScene.MeshesList.Add(babylonMesh);
 
@@ -34,7 +125,7 @@ namespace Unity3D2Babylon
             }
         }
 
-        private void ConvertUnityMeshToBabylon(Mesh mesh, Transform transform, GameObject gameObject, float progress)
+        private void ConvertUnityMeshToBabylon(Mesh mesh, Transform transform, GameObject gameObject, float progress, BabylonAbstractMesh[] instances = null)
         {
             BabylonMesh babylonMesh = new BabylonMesh();
             var renderer = gameObject.GetComponent<Renderer>();
@@ -46,15 +137,7 @@ namespace Unity3D2Babylon
             babylonMesh.receiveShadows = renderer.receiveShadows;
 
             babylonMesh.parentId = GetParentID(transform);
-
-            babylonMesh.position = transform.localPosition.ToFloat();
-
-            babylonMesh.rotation = new float[3];
-            babylonMesh.rotation[0] = transform.localRotation.eulerAngles.x * (float)Math.PI / 180;
-            babylonMesh.rotation[1] = transform.localRotation.eulerAngles.y * (float)Math.PI / 180;
-            babylonMesh.rotation[2] = transform.localRotation.eulerAngles.z * (float)Math.PI / 180;
-
-            babylonMesh.scaling = transform.localScale.ToFloat();
+            ConvertTransform(babylonMesh, transform, gameObject, instances);
 
             babylonMesh.positions = new float[mesh.vertexCount * 3];
 

+ 69 - 9
Exporters/Unity 5/Unity3D2Babylon/SceneBuilder.cs

@@ -7,6 +7,7 @@ using UnityEngine;
 using Object = UnityEngine.Object;
 using JsonFx.Serialization;
 using JsonFx.Serialization.Resolvers;
+using UnityEditor;
 
 namespace Unity3D2Babylon
 {
@@ -108,10 +109,52 @@ namespace Unity3D2Babylon
             var itemsCount = gameObjects.Length;
 
             var index = 0;
+
+            //Dictionary to store prefabs and their instances
+            Dictionary<GameObject, List<BabylonAbstractMesh>> dicPrefabs = new Dictionary<GameObject, List<BabylonAbstractMesh>>();
+
             foreach (var gameObject in gameObjects)
             {
                 var progress = ((float)index / itemsCount);
                 index++;
+
+                /* 
+                    The order of processing is important here.
+                    We will only check if this is a mesh prefab if it is not a light or camera
+                */
+
+                // Light
+                var light = gameObject.GetComponent<Light>();
+                if (light != null)
+                {
+                    ConvertUnityLightToBabylon(light, progress);
+                    continue;
+                }
+
+                // Camera
+                var camera = gameObject.GetComponent<Camera>();
+                if (camera != null)
+                {
+                    ConvertUnityCameraToBabylon(camera, progress);
+                    continue;
+                }
+
+                // Check if this is a prefab instance
+                GameObject gobjPrefab = (GameObject)PrefabUtility.GetPrefabParent(gameObject);
+                if (gobjPrefab != null)
+                {
+                    //Add prefab to dictionary if it doesn't already exist
+                    if (!dicPrefabs.ContainsKey(gobjPrefab))
+                    {
+                        dicPrefabs[gobjPrefab] = new List<BabylonAbstractMesh>();
+                    }
+
+                    List<BabylonAbstractMesh> lstInstances = dicPrefabs[gobjPrefab];
+                    BabylonAbstractMesh instance = ConvertUnityMeshToInstance(gameObject);
+                    lstInstances.Add(instance);
+                    continue;
+                }
+
                 // Static meshes
                 var meshFilter = gameObject.GetComponent<MeshFilter>();
                 if (meshFilter != null)
@@ -128,24 +171,41 @@ namespace Unity3D2Babylon
                     continue;
                 }
 
-                // Light
-                var light = gameObject.GetComponent<Light>();
-                if (light != null)
+                // Empty
+                ConvertUnityEmptyObjectToBabylon(gameObject);
+            }
+
+            index = 0;
+            itemsCount = dicPrefabs.Count;
+
+            //Convert prefabs
+            foreach (KeyValuePair<GameObject, List<BabylonAbstractMesh>> pair in dicPrefabs)
+            {
+                var progress = ((float)index / itemsCount);
+                index++;
+
+                List<BabylonAbstractMesh> lstValue = pair.Value;
+                GameObject prefab = pair.Key;
+                BabylonAbstractMesh[] lstInstance = lstValue.ToArray();
+
+                // Static meshes
+                var meshFilter = prefab.GetComponent<MeshFilter>();
+                if (meshFilter != null)
                 {
-                    ConvertUnityLightToBabylon(light, progress);
+                    ConvertUnityMeshToBabylon(meshFilter.sharedMesh, meshFilter.transform, prefab, progress, lstInstance);
                     continue;
                 }
 
-                // Camera
-                var camera = gameObject.GetComponent<Camera>();
-                if (camera != null)
+                // Skinned meshes
+                var skinnedMesh = prefab.GetComponent<SkinnedMeshRenderer>();
+                if (skinnedMesh != null)
                 {
-                    ConvertUnityCameraToBabylon(camera, progress);
+                    ConvertUnityMeshToBabylon(skinnedMesh.sharedMesh, skinnedMesh.transform, prefab, progress, lstInstance);
                     continue;
                 }
 
                 // Empty
-                ConvertUnityEmptyObjectToBabylon(gameObject);
+                ConvertUnityEmptyObjectToBabylon(prefab, lstInstance);
             }
 
             // Materials

+ 1 - 2
Tools/Gulp/config.json

@@ -60,7 +60,6 @@
       "../../src/Materials/Textures/babylon.dynamicTexture.js",
       "../../src/Materials/Textures/babylon.videoTexture.js",
       "../../src/Materials/Textures/Procedurals/babylon.customProceduralTexture.js",
-      "../../src/Materials/Textures/babylon.proceduralTexture.js",
       "../../src/Materials/babylon.effect.js",
       "../../src/Materials/babylon.material.js",
       "../../src/Materials/babylon.standardMaterial.js",
@@ -174,4 +173,4 @@
       "../../src/Particles/babylon.solidParticleSystem.js"
     ]
   }
-}
+}

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


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


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


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


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


+ 86 - 83
dist/preview release/what's new.md

@@ -1,83 +1,86 @@
-- 2.3.0:
-  - **Major updates**
-    - Point lights shadow mapping. [Demo here](http://www.babylonjs-playground.com/#LYCSQ#12) ([deltakosh](https://github.com/deltakosh))
-    - Introducing [Materials Library](https://github.com/BabylonJS/Babylon.js/tree/master/materialsLibrary) ([deltakosh](https://github.com/deltakosh))
-      - Water material: http://doc.babylonjs.com/extensions/Water ([julien-moreau](https://github.com/julien-moreau))
-      - Fire material: http://doc.babylonjs.com/extensions/fire ([julien-moreau](https://github.com/julien-moreau))
-      - Normal material: http://doc.babylonjs.com/extensions/normal ([temechon](https://github.com/temechon))
-      - Lava Material: http://doc.babylonjs.com/extensions/lava ([temechon](https://github.com/temechon))
-      - PBR Material: http://doc.babylonjs.com/extensions/pbr ([deltakosh](https://github.com/deltakosh))
-    - New cache mecanism for StandardMaterial ([deltakosh](https://github.com/deltakosh))
-    - New Solid Particle System ([jerome](https://github.com/jbousquie))
-    - New `StandardMaterial.lightmapTexture` which can be controlled with `StandardMaterial.useLightmapAsShadowMap` ([deltakosh](https://github.com/deltakosh))
-    - Support for reflection probes. [See documentation here](http://doc.babylonjs.com/tutorials/How_to_use_Reflection_probes) ([deltakosh](https://github.com/deltakosh))
-    - New serializers [folder](https://github.com/BabylonJS/Babylon.js/serializers) to host .babylon serializers ([deltakosh](https://github.com/deltakosh))
-      - New .obj serializer ([BitOfGold](https://github.com/BitOfGold))
-    - Sprites now can be [picked](http://www.babylonjs-playground.com/#1XMVZW#4) and can use [actions](http://www.babylonjs-playground.com/#9RUHH#4) ([deltakosh](https://github.com/deltakosh))
-    - New `Mesh.CreatePolyhedron()` method ([jerome](https://github.com/jbousquie))
-    - New `Mesh.CreateIcoSphere()` method. [Demo here](http://www.babylonjs-playground.com/#24DUYD) (G'kar)
-    - Introducing [babylon.core.js](http://doc.babylonjs.com/generals/Framework_versions) ([deltakosh](https://github.com/deltakosh))
-  - **Updates**
-    - New button to log the camera position in the debug layer ([temechon](https://github.com/temechon))
-    - Added `Animatable.goToFrame()` ([deltakosh](https://github.com/deltakosh))   
-    - Fixed behavior or `Animation.CreateAndStartAnimation` and added `Animation.CreateMergeAndStartAnimation` to reproduce previous behavior ([deltakosh](https://github.com/deltakosh))
-    - Adding `StandardMaterial.linkEmissiveWithDiffuse` to, well, link emissive with diffuse value. (With)[http://www.babylonjs-playground.com/#2FPUCS#2] and (without)[http://www.babylonjs-playground.com/#2FPUCS#1] ([deltakosh](https://github.com/deltakosh))
-    - Adding support for equi-rectangular mapping. See [demo here](http://www.babylonjs-playground.com/#27FN5R#12) ([deltakosh](https://github.com/deltakosh))
-    - Sprites and particles scheduler updated to be resolved before transparent objects ([deltakosh](https://github.com/deltakosh))
-    - Added ability to deactivate ArcRotateCamera panning mechanism (by setting panningSensibility to 0) ([vouskprod](http://www.github.com/vousk))    
-    - Added `DirectionalLight.autoUpdateExtends` to prevent directional lights to adapt to scene extends ([deltakosh](https://github.com/deltakosh))
-    - Added a new parameter to `debugLayer.show()` to define root element to use ([deltakosh](https://github.com/deltakosh))
-    - New `MeshBuilder` class used to create all kind of mesh shapes ([deltakosh](https://github.com/deltakosh))
-    - Added `Scene.constantlyUpdateMeshUnderPointer` to improve performance when moving mouse ([deltakosh](https://github.com/deltakosh))
-    - Added `StandardMaterial.disableLighting` ([deltakosh](https://github.com/deltakosh))
-    - Improved reflection shader performance ([deltakosh](https://github.com/deltakosh))
-    - New `Material.sideOrientation` property to define clockwise or counter-clockwise faces selection. [Demo here](http://www.babylonjs-playground.com/#1TZJQY) ([deltakosh](https://github.com/deltakosh))
-    - It is now possible to create a custom loading screen. [PR](https://github.com/BabylonJS/Babylon.js/pull/700) ([RaananW](https://github.com/RaananW))
-    - Per face color and texture feature in `MeshBuilder.CreateCylinder()` ([jerome](https://github.com/jbousquie))
-    - _Arc_ feature in `CreateCylinder`, `CreateSphere`, `CreateTube`, `CreateDisc` and `CreateLathe` ([jerome](https://github.com/jbousquie))
-    - _Slice_ feature in `MeshBuilder.CreateSphere()` ([jerome](https://github.com/jbousquie))
-    - `closed` parameter in `MeshBuilder.CreateLathe()` ([jerome](https://github.com/jbousquie))
-    - `diameter`, `hasRings`, `enclose` parameters in `MeshBuilder.CreateCreateCylinder()` ([jerome](https://github.com/jbousquie))
-    - `Material.dispose()` now removes disposed material from meshes ([deltakosh](https://github.com/deltakosh))
-    - New `Material.getBindedMeshes()` function ([deltakosh](https://github.com/deltakosh))
-    - OimoJS Plugin now uses Quaternions exclusively and calculates body rotations correctly. [PR](https://github.com/BabylonJS/Babylon.js/pull/761) ([RaananW](https://github.com/RaananW))
-    - It is now possible to get the physics engine's body and wolrd objects using the physics engine. [PR](https://github.com/BabylonJS/Babylon.js/pull/761) ([RaananW](https://github.com/RaananW))
-    - new Heightmap Impostor for Cannon.js physics engine. [PR](https://github.com/BabylonJS/Babylon.js/pull/78), [Demo] (http://www.babylonjs-playground.com/#D3LQD#3) ([RaananW](https://github.com/RaananW))
-    - A plane mesh can be created with a source plane (math). [PR](https://github.com/BabylonJS/Babylon.js/pull/779) ([RaananW](https://github.com/RaananW))
-    - AbstractMesh.onPhysicsCollide will be triggered when a physics-enabled mesh collides against another. [PR](https://github.com/BabylonJS/Babylon.js/pull/806) ([RaananW](https://github.com/RaananW))
-    - Added scene onPointerMove public callback. [PR](https://github.com/BabylonJS/Babylon.js/pull/810) ([RaananW](https://github.com/RaananW))
-    - Added streaming support for BABYLON.Sound ([davrous](https://github.com/davrous))
-    - Added collisionsEnabled and workerCollisions for serialization [PR](https://github.com/BabylonJS/Babylon.js/pull/830) ([Dad72](https://github.com/dad72))
-  - **Bug fixes**
-    - Fixed a bug with spherical mapping ([deltakosh](https://github.com/deltakosh)) 
-    - Fixed a bug with clone and createInstance which was forcing the recomputation of bounding boxes ([deltakosh](https://github.com/deltakosh)) 
-    - Fixed a bug with CSG when submeshes are kept ([deltakosh](https://github.com/deltakosh)) 
-    - Fixed a bug with texture coordinates matrices ([deltakosh](https://github.com/deltakosh))
-    - Fixed Sphere texture coordinates generation ([deltakosh](https://github.com/deltakosh))
-    - Fixed a bug with `Mesh.attachToBone` when bone's matrix has a negative determinant ([deltakosh](https://github.com/deltakosh))
-    - Fixed a possible but with the active camera while taking a screenshot. [PR](https://github.com/BabylonJS/Babylon.js/pull/701) ([RaananW](https://github.com/RaananW))
-    - Fixed a bug with worker-collisions and instances. [PR](https://github.com/BabylonJS/Babylon.js/pull/705) ([RaananW](https://github.com/RaananW))
-    - Fixed a bug with removed meshes and geometries from the worker-cache. [PR](https://github.com/BabylonJS/Babylon.js/pull/711) ([RaananW](https://github.com/RaananW))
-    - Fixed `closePath` and `closeArray` ribbon parameter now working back together ([jerome](https://github.com/jbousquie))
-    - Fixed morphing on capped tubes  ([jerome](https://github.com/jbousquie))
-    - Fixed morphing on extruded shapes  ([jerome](https://github.com/jbousquie))
-    - Fixed tube and extruded shape cap light artifact  ([jerome](https://github.com/jbousquie))
-    - Fixed a bug calculating velocity during collision with gravity enabled. [PR](https://github.com/BabylonJS/Babylon.js/pull/738) ([RaananW](https://github.com/RaananW))
-    - Fixed a bug in instance serialization. [PR](https://github.com/BabylonJS/Babylon.js/pull/726) ([RaananW](https://github.com/RaananW))
-  - **Breaking changes**
-    - `VertexData.CreateCylinder()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
-    - `VertexData.CreateRibbon()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
-    - `VertexData.CreateBox()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
-    - `VertexData.CreateSphere)` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
-    - `VertexData.CreateTorus()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
-    - `VertexData.CreateTorusKnot()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
-    - `VertexData.CreatePlane()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
-    - `VertexData.CreateDisc()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
-    - `VertexData.CreateLines()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
-    - `VertexData.CreateDashedLines()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
-    - `VertexData.CreateGround()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
-    - `VertexData.CreateTiledGround()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
-    - `VertexData.CreateGroundFromHeightMap()` now supports only the single _options_ parameter ([deltakosh](https://github.com/deltakosh))
-    - `Tools.IsExponantOfTwo()` renamed to `Tools.IsExponentOfTwo()` ([deltakosh](https://github.com/deltakosh))
-    - `Tools.GetExponantOfTwo()` renamed to `Tools.GetExponentOfTwo()` ([deltakosh](https://github.com/deltakosh))
-    - Updated Cannon.js plugin to the newest version (0.6.2). New cannon.js must be used. [PR](https://github.com/BabylonJS/Babylon.js/pull/755) ([RaananW](https://github.com/RaananW))
+- 2.3.0:
+  - **Major updates**
+    - Point lights shadow mapping. [Demo here](http://www.babylonjs-playground.com/#LYCSQ#12) ([deltakosh](https://github.com/deltakosh))
+    - Introducing [Materials Library](https://github.com/BabylonJS/Babylon.js/tree/master/materialsLibrary) ([deltakosh](https://github.com/deltakosh))
+      - Water material: http://doc.babylonjs.com/extensions/Water ([julien-moreau](https://github.com/julien-moreau))
+      - Fire material: http://doc.babylonjs.com/extensions/fire ([julien-moreau](https://github.com/julien-moreau))
+      - Normal material: http://doc.babylonjs.com/extensions/normal ([temechon](https://github.com/temechon))
+      - Lava Material: http://doc.babylonjs.com/extensions/lava ([temechon](https://github.com/temechon))
+      - PBR Material: http://doc.babylonjs.com/extensions/pbr ([deltakosh](https://github.com/deltakosh))
+    - New cache mecanism for StandardMaterial ([deltakosh](https://github.com/deltakosh))
+    - New Solid Particle System ([jerome](https://github.com/jbousquie))
+    - New `StandardMaterial.lightmapTexture` which can be controlled with `StandardMaterial.useLightmapAsShadowMap` ([deltakosh](https://github.com/deltakosh))
+    - Support for reflection probes. [See documentation here](http://doc.babylonjs.com/tutorials/How_to_use_Reflection_probes) ([deltakosh](https://github.com/deltakosh))
+    - New serializers [folder](https://github.com/BabylonJS/Babylon.js/serializers) to host .babylon serializers ([deltakosh](https://github.com/deltakosh))
+      - New .obj serializer ([BitOfGold](https://github.com/BitOfGold))
+    - Sprites now can be [picked](http://www.babylonjs-playground.com/#1XMVZW#4) and can use [actions](http://www.babylonjs-playground.com/#9RUHH#4) ([deltakosh](https://github.com/deltakosh))
+    - New `Mesh.CreatePolyhedron()` method ([jerome](https://github.com/jbousquie))
+    - New `Mesh.CreateIcoSphere()` method. [Demo here](http://www.babylonjs-playground.com/#24DUYD) (G'kar)
+    - Introducing [babylon.core.js](http://doc.babylonjs.com/generals/Framework_versions) ([deltakosh](https://github.com/deltakosh))
+  - **Updates**
+	- Unity3D exporter will recognise instances of prefabs ([ozRocker](https://github.com/punkoffice))
+    - New parse mechanism (for loading .babylon file) ([deltakosh](https://github.com/deltakosh))   
+    - New button to log the camera position in the debug layer ([temechon](https://github.com/temechon))
+    - Added `Animatable.goToFrame()` ([deltakosh](https://github.com/deltakosh))   
+    - Fixed behavior or `Animation.CreateAndStartAnimation` and added `Animation.CreateMergeAndStartAnimation` to reproduce previous behavior ([deltakosh](https://github.com/deltakosh))
+    - Adding `StandardMaterial.linkEmissiveWithDiffuse` to, well, link emissive with diffuse value. (With)[http://www.babylonjs-playground.com/#2FPUCS#2] and (without)[http://www.babylonjs-playground.com/#2FPUCS#1] ([deltakosh](https://github.com/deltakosh))
+    - Adding support for equi-rectangular mapping. See [demo here](http://www.babylonjs-playground.com/#27FN5R#12) ([deltakosh](https://github.com/deltakosh))
+    - Sprites and particles scheduler updated to be resolved before transparent objects ([deltakosh](https://github.com/deltakosh))
+    - Added ability to deactivate ArcRotateCamera panning mechanism (by setting panningSensibility to 0) ([vouskprod](http://www.github.com/vousk))    
+    - Added `DirectionalLight.autoUpdateExtends` to prevent directional lights to adapt to scene extends ([deltakosh](https://github.com/deltakosh))
+    - Added a new parameter to `debugLayer.show()` to define root element to use ([deltakosh](https://github.com/deltakosh))
+    - New `MeshBuilder` class used to create all kind of mesh shapes ([deltakosh](https://github.com/deltakosh))
+    - Added `Scene.constantlyUpdateMeshUnderPointer` to improve performance when moving mouse ([deltakosh](https://github.com/deltakosh))
+    - Added `StandardMaterial.disableLighting` ([deltakosh](https://github.com/deltakosh))
+    - Improved reflection shader performance ([deltakosh](https://github.com/deltakosh))
+    - New `Material.sideOrientation` property to define clockwise or counter-clockwise faces selection. [Demo here](http://www.babylonjs-playground.com/#1TZJQY) ([deltakosh](https://github.com/deltakosh))
+    - It is now possible to create a custom loading screen. [PR](https://github.com/BabylonJS/Babylon.js/pull/700) ([RaananW](https://github.com/RaananW))
+    - Per face color and texture feature in `MeshBuilder.CreateCylinder()` ([jerome](https://github.com/jbousquie))
+    - _Arc_ feature in `CreateCylinder`, `CreateSphere`, `CreateTube`, `CreateDisc` and `CreateLathe` ([jerome](https://github.com/jbousquie))
+    - _Slice_ feature in `MeshBuilder.CreateSphere()` ([jerome](https://github.com/jbousquie))
+    - `closed` parameter in `MeshBuilder.CreateLathe()` ([jerome](https://github.com/jbousquie))
+    - `diameter`, `hasRings`, `enclose` parameters in `MeshBuilder.CreateCreateCylinder()` ([jerome](https://github.com/jbousquie))
+    - `Material.dispose()` now removes disposed material from meshes ([deltakosh](https://github.com/deltakosh))
+    - New `Material.getBindedMeshes()` function ([deltakosh](https://github.com/deltakosh))
+    - OimoJS Plugin now uses Quaternions exclusively and calculates body rotations correctly. [PR](https://github.com/BabylonJS/Babylon.js/pull/761) ([RaananW](https://github.com/RaananW))
+    - It is now possible to get the physics engine's body and wolrd objects using the physics engine. [PR](https://github.com/BabylonJS/Babylon.js/pull/761) ([RaananW](https://github.com/RaananW))
+    - new Heightmap Impostor for Cannon.js physics engine. [PR](https://github.com/BabylonJS/Babylon.js/pull/78), [Demo] (http://www.babylonjs-playground.com/#D3LQD#3) ([RaananW](https://github.com/RaananW))
+    - A plane mesh can be created with a source plane (math). [PR](https://github.com/BabylonJS/Babylon.js/pull/779) ([RaananW](https://github.com/RaananW))
+    - AbstractMesh.onPhysicsCollide will be triggered when a physics-enabled mesh collides against another. [PR](https://github.com/BabylonJS/Babylon.js/pull/806) ([RaananW](https://github.com/RaananW))
+    - Added scene onPointerMove public callback. [PR](https://github.com/BabylonJS/Babylon.js/pull/810) ([RaananW](https://github.com/RaananW))
+    - Added streaming support for BABYLON.Sound ([davrous](https://github.com/davrous))
+    - Added collisionsEnabled and workerCollisions for serialization [PR](https://github.com/BabylonJS/Babylon.js/pull/830) ([Dad72](https://github.com/dad72))
+  - **Bug fixes**
+    - Fixed a bug with spherical mapping ([deltakosh](https://github.com/deltakosh)) 
+    - Fixed a bug with clone and createInstance which was forcing the recomputation of bounding boxes ([deltakosh](https://github.com/deltakosh)) 
+    - Fixed a bug with CSG when submeshes are kept ([deltakosh](https://github.com/deltakosh)) 
+    - Fixed a bug with texture coordinates matrices ([deltakosh](https://github.com/deltakosh))
+    - Fixed Sphere texture coordinates generation ([deltakosh](https://github.com/deltakosh))
+    - Fixed a bug with `Mesh.attachToBone` when bone's matrix has a negative determinant ([deltakosh](https://github.com/deltakosh))
+    - Fixed a possible but with the active camera while taking a screenshot. [PR](https://github.com/BabylonJS/Babylon.js/pull/701) ([RaananW](https://github.com/RaananW))
+    - Fixed a bug with worker-collisions and instances. [PR](https://github.com/BabylonJS/Babylon.js/pull/705) ([RaananW](https://github.com/RaananW))
+    - Fixed a bug with removed meshes and geometries from the worker-cache. [PR](https://github.com/BabylonJS/Babylon.js/pull/711) ([RaananW](https://github.com/RaananW))
+    - Fixed `closePath` and `closeArray` ribbon parameter now working back together ([jerome](https://github.com/jbousquie))
+    - Fixed morphing on capped tubes  ([jerome](https://github.com/jbousquie))
+    - Fixed morphing on extruded shapes  ([jerome](https://github.com/jbousquie))
+    - Fixed tube and extruded shape cap light artifact  ([jerome](https://github.com/jbousquie))
+    - Fixed a bug calculating velocity during collision with gravity enabled. [PR](https://github.com/BabylonJS/Babylon.js/pull/738) ([RaananW](https://github.com/RaananW))
+    - Fixed a bug in instance serialization. [PR](https://github.com/BabylonJS/Babylon.js/pull/726) ([RaananW](https://github.com/RaananW))
+    - Fixed a memory leak with textures ([deltakosh](https://github.com/deltakosh)) 
+  - **Breaking changes**
+    - `VertexData.CreateCylinder()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
+    - `VertexData.CreateRibbon()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
+    - `VertexData.CreateBox()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
+    - `VertexData.CreateSphere)` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
+    - `VertexData.CreateTorus()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
+    - `VertexData.CreateTorusKnot()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
+    - `VertexData.CreatePlane()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
+    - `VertexData.CreateDisc()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
+    - `VertexData.CreateLines()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
+    - `VertexData.CreateDashedLines()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
+    - `VertexData.CreateGround()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
+    - `VertexData.CreateTiledGround()` now supports only the single _options_ parameter ([jerome](https://github.com/jbousquie))
+    - `VertexData.CreateGroundFromHeightMap()` now supports only the single _options_ parameter ([deltakosh](https://github.com/deltakosh))
+    - `Tools.IsExponantOfTwo()` renamed to `Tools.IsExponentOfTwo()` ([deltakosh](https://github.com/deltakosh))
+    - `Tools.GetExponantOfTwo()` renamed to `Tools.GetExponentOfTwo()` ([deltakosh](https://github.com/deltakosh))
+    - Updated Cannon.js plugin to the newest version (0.6.2). New cannon.js must be used. [PR](https://github.com/BabylonJS/Babylon.js/pull/755) ([RaananW](https://github.com/RaananW))

+ 41 - 42
loaders/glTF/README.md

@@ -1,42 +1,41 @@
-# Babylon.js glTF File Loader
-
-# Usage
-The glTF file loader is a SceneLoader plugin.
-Just reference the loader in your HTML file:
-
-```
-<script src="babylon.2.1.js"></script>
-<script src="babylon.glTFFileLoader.js"></script>
-```
-
-And then, call the scene loader:
-```
-BABYLON.SceneLoader.Load("./", "duck.gltf", engine, function (scene) { 
-   // do somethings with the scene
-});
-```
-
-## Supported features
-* Load scenes (SceneLoader.Load)
-* Import geometries
-    * From binary files
-    * From base64 buffers
-* Import lights
-* Import cameras
-* Import and set custom shaders (if no shaders, the Babylon.js default material is applied)
-    * Automatically bind attributes
-    * Automatically bind matrices
-    * Set uniforms
-* Import and set animations
-* Skinning
-    * Skeletons
-    * Hardware skinning (shaders support)
-* Handle dummy nodes (empty nodes)
-
-## Unsupported features
-* ImportMesh function
-* Skinning
-    * Bones animations
-
-## To improve
-* Bones import
+# Babylon.js glTF File Loader
+
+# Usage
+The glTF file loader is a SceneLoader plugin.
+Just reference the loader in your HTML file:
+
+```
+<script src="babylon.2.1.js"></script>
+<script src="babylon.glTFFileLoader.js"></script>
+```
+
+And then, call the scene loader:
+```
+BABYLON.SceneLoader.Load("./", "duck.gltf", engine, function (scene) { 
+   // do somethings with the scene
+});
+```
+
+## Supported features
+* Load scenes (SceneLoader.Load)
+* Import geometries
+    * From binary files
+    * From base64 buffers
+* Import lights
+* Import cameras
+* Import and set custom shaders (if no shaders, the Babylon.js default material is applied)
+    * Automatically bind attributes
+    * Automatically bind matrices
+    * Set uniforms
+* Import and set animations
+* Skinning
+    * Skeletons
+    * Hardware skinning (shaders support)
+    * Bones import
+* Handle dummy nodes (empty nodes)
+
+## Unsupported features
+* ImportMesh function
+
+## To improve
+* Test on more models

Plik diff jest za duży
+ 1306 - 1166
loaders/glTF/babylon.glTFFileLoader.js


Plik diff jest za duży
+ 1533 - 1388
loaders/glTF/babylon.glTFFileLoader.ts


+ 263 - 279
loaders/glTF/babylon.glTFFileLoaderInterfaces.ts

@@ -1,280 +1,264 @@
-module BABYLON {
-    /**
-    * Interfaces
-    */
-    export interface IGLTFChildRootProperty {
-        name?: string;
-    }
-
-    export interface IGLTFAccessor extends IGLTFChildRootProperty {
-        bufferView: string;
-        byteOffset: number;
-        byteStride: number;
-        count: number;
-        type: string;
-        componentType: EComponentType;
-
-        max?: number[],
-        min?: number[],
-        name?: string;
-    }
-
-    export interface IGLTFBufferView extends IGLTFChildRootProperty {
-        buffer: string;
-        byteOffset: number;
-        byteLength: number;
-
-        target?: number;
-    }
-
-    export interface IGLTFBuffer extends IGLTFChildRootProperty {
-        uri: string;
-
-        byteLength?: number;
-        type?: string;
-    }
-
-    export interface IGLTFShader extends IGLTFChildRootProperty {
-        uri: string;
-        type: EShaderType;
-    }
-
-    export interface IGLTFProgram extends IGLTFChildRootProperty {
-        attributes: string[];
-        fragmentShader: string;
-        vertexShader: string;
-    }
-
-    export interface IGLTFTechniqueParameter {
-        type: number;
-
-        count?: number;
-        semantic?: string;
-        node?: string;
-        value?: number|boolean|string|Array<any>;
-        source?: string;
-
-        babylonValue?: any;
-    }
-
-    export interface IGLTFTechniquePassCommonProfile {
-        lightingModel: string;
-        texcoordBindings: Object;
-
-        parameters?: Array<any>;
-    }
-
-    export interface IGLTFTechniquePassInstanceProgram {
-        program: string;
-
-        attributes?: Object;
-        uniforms: Object;
-    }
-
-    export interface IGLTFTechniquePassStatesFunctions {
-        blendColor?: number[];
-        blendEquationSeparate?: number[];
-        blendFuncSeparate?: number[];
-    }
-
-    export interface IGLTFTechniquePassStates {
-        enable: number[];
-        functions: IGLTFTechniquePassStatesFunctions;
-    }
-
-    export interface IGLTFTechniquePassDetails {
-        commonProfile: IGLTFTechniquePassCommonProfile;
-        type: string;
-    }
-
-    export interface IGLTFTechniquePass {
-        details: IGLTFTechniquePassDetails;
-        instanceProgram: IGLTFTechniquePassInstanceProgram;
-        states: IGLTFTechniquePassStates;
-    }
-
-    export interface IGLTFTechnique extends IGLTFChildRootProperty {
-        parameters: Object;
-        pass: string;
-        passes: Object;
-    }
-
-    export interface IGLTFMaterialInstanceTechnique {
-        technique: string;
-
-        values?: Object;
-    }
-
-    export interface IGLTFMaterial extends IGLTFChildRootProperty {
-        instanceTechnique: IGLTFMaterialInstanceTechnique;
-    }
-
-    export interface IGLTFMeshPrimitive {
-        attributes: Object;
-        indices: string;
-        material: string;
-
-        primitive?: number;
-    }
-
-    export interface IGLTFMesh extends IGLTFChildRootProperty {
-        primitives: IGLTFMeshPrimitive[];
-    }
-
-    export interface IGLTFImage extends IGLTFChildRootProperty {
-        uri: string;
-    }
-
-    export interface IGLTFSampler extends IGLTFChildRootProperty {
-        magFilter?: number;
-        minFilter?: number;
-        wrapS?: number;
-        wrapT?: number;
-    }
-
-    export interface IGLTFTexture extends IGLTFChildRootProperty {
-        sampler: string;
-        source: string;
-
-        format?: ETextureFormat;
-        internalFormat?: ETextureFormat;
-        target?: number;
-        type?: number;
-        
-        // Babylon.js values (optimize)
-        babylonTexture?: Texture;
-    }
-
-    export interface IGLTFAmbienLight {
-        color?: number[];
-    }
-
-    export interface IGLTFDirectionalLight {
-        color?: number[];
-    }
-
-    export interface IGLTFPointLight {
-        color?: number[];
-        constantAttenuation?: number;
-        linearAttenuation?: number;
-        quadraticAttenuation?: number;
-    }
-
-    export interface IGLTFSpotLight {
-        color?: number[];
-        constantAttenuation?: number;
-        fallOfAngle?: number;
-        fallOffExponent?: number;
-        linearAttenuation?: number;
-        quadraticAttenuation?: number;
-    }
-
-    export interface IGLTFLight extends IGLTFChildRootProperty {
-        type: string;
-    }
-
-    export interface IGLTFCameraOrthographic {
-        xmag: number;
-        ymag: number;
-        zfar: number;
-        znear: number;
-    }
-
-    export interface IGLTFCameraPerspective {
-        aspectRatio: number;
-        yfov: number;
-        zfar: number;
-        znear: number;
-    }
-
-    export interface IGLTFCamera extends IGLTFChildRootProperty {
-        type: string;
-    }
-
-    export interface IGLTFAnimationChannelTarget {
-        id: string;
-        path: string;
-    }
-
-    export interface IGLTFAnimationChannel {
-        sampler: string;
-        target: IGLTFAnimationChannelTarget;
-    }
-
-    export interface IGLTFAnimationSampler {
-        input: string;
-        output: string;
-
-        interpolation?: string;
-    }
-
-    export interface IGLTFAnimation extends IGLTFChildRootProperty {
-        channels?: IGLTFAnimationChannel[];
-        parameters?: Object;
-        samplers?: Object;
-    }
-
-    export interface IGLTFNodeInstanceSkin {
-        skeletons: string[];
-        skin: string;
-        meshes: string[];
-    }
-
-    export interface IGLTFSkins extends IGLTFChildRootProperty {
-        bindShapeMatrix: number[];
-        inverseBindMatrices: string;
-        jointNames: string[];
-    }
-
-    export interface IGLTFNode extends IGLTFChildRootProperty {
-        camera?: string;
-        children: string[];
-        instanceSkin?: IGLTFNodeInstanceSkin;
-        jointName?: string;
-        light?: string;
-        matrix: number[];
-        mesh?: string;
-        meshes?: string[];
-        rotation?: number[];
-        scale?: number[];
-        translation?: number[];
-    }
-
-    export interface IGLTFScene extends IGLTFChildRootProperty {
-        nodes: string[];
-    }
-
-    /**
-    * Runtime
-    */
-    export interface IGLTFRuntime {
-        accessors: Object;
-        buffers: Object;
-        bufferViews: Object;
-        meshes: Object;
-        lights: Object;
-        cameras: Object;
-        nodes: Object;
-        images: Object;
-        textures: Object;
-        shaders: Object;
-        programs: Object;
-        samplers: Object;
-        techniques: Object;
-        materials: Object;
-        animations: Object;
-        skins: Object;
-        currentScene: Object;
-
-        buffersCount: number;
-        shaderscount: number;
-
-        scene: Scene;
-        rootUrl: string;
-        loadedBuffers: number;
-        loadedShaders: number;
-        arrayBuffers: Object;
-
-        dummyNodes: Node[];
-    }
+module BABYLON {
+    /**
+    * Interfaces
+    */
+    export interface IGLTFChildRootProperty {
+        name?: string;
+    }
+
+    export interface IGLTFAccessor extends IGLTFChildRootProperty {
+        bufferView: string;
+        byteOffset: number;
+        byteStride: number;
+        count: number;
+        type: string;
+        componentType: EComponentType;
+
+        max?: number[],
+        min?: number[],
+        name?: string;
+    }
+
+    export interface IGLTFBufferView extends IGLTFChildRootProperty {
+        buffer: string;
+        byteOffset: number;
+        byteLength: number;
+
+        target?: number;
+    }
+
+    export interface IGLTFBuffer extends IGLTFChildRootProperty {
+        uri: string;
+
+        byteLength?: number;
+        type?: string;
+    }
+
+    export interface IGLTFShader extends IGLTFChildRootProperty {
+        uri: string;
+        type: EShaderType;
+    }
+
+    export interface IGLTFProgram extends IGLTFChildRootProperty {
+        attributes: string[];
+        fragmentShader: string;
+        vertexShader: string;
+    }
+
+    export interface IGLTFTechniqueParameter {
+        type: number;
+
+        count?: number;
+        semantic?: string;
+        node?: string;
+        value?: number|boolean|string|Array<any>;
+        source?: string;
+
+        babylonValue?: any;
+    }
+
+    export interface IGLTFTechniqueCommonProfile {
+        lightingModel: string;
+        texcoordBindings: Object;
+
+        parameters?: Array<any>;
+    }
+
+    export interface IGLTFTechniqueStatesFunctions {
+        blendColor?: number[];
+        blendEquationSeparate?: number[];
+        blendFuncSeparate?: number[];
+        colorMask: boolean[];
+        cullFace: number[];
+    }
+
+    export interface IGLTFTechniqueStates {
+        enable: number[];
+        functions: IGLTFTechniqueStatesFunctions;
+    }
+
+    export interface IGLTFTechnique extends IGLTFChildRootProperty {
+        parameters: Object;
+        program: string;
+
+        attributes: Object;
+        uniforms: Object;
+        states: IGLTFTechniqueStates;
+    }
+
+    export interface IGLTFMaterial extends IGLTFChildRootProperty {
+        technique?: string;
+        values: string[];
+    }
+
+    export interface IGLTFMeshPrimitive {
+        attributes: Object;
+        indices: string;
+        material: string;
+
+        primitive?: number;
+    }
+
+    export interface IGLTFMesh extends IGLTFChildRootProperty {
+        primitives: IGLTFMeshPrimitive[];
+    }
+
+    export interface IGLTFImage extends IGLTFChildRootProperty {
+        uri: string;
+    }
+
+    export interface IGLTFSampler extends IGLTFChildRootProperty {
+        magFilter?: number;
+        minFilter?: number;
+        wrapS?: number;
+        wrapT?: number;
+    }
+
+    export interface IGLTFTexture extends IGLTFChildRootProperty {
+        sampler: string;
+        source: string;
+
+        format?: ETextureFormat;
+        internalFormat?: ETextureFormat;
+        target?: number;
+        type?: number;
+        
+        // Babylon.js values (optimize)
+        babylonTexture?: Texture;
+    }
+
+    export interface IGLTFAmbienLight {
+        color?: number[];
+    }
+
+    export interface IGLTFDirectionalLight {
+        color?: number[];
+    }
+
+    export interface IGLTFPointLight {
+        color?: number[];
+        constantAttenuation?: number;
+        linearAttenuation?: number;
+        quadraticAttenuation?: number;
+    }
+
+    export interface IGLTFSpotLight {
+        color?: number[];
+        constantAttenuation?: number;
+        fallOfAngle?: number;
+        fallOffExponent?: number;
+        linearAttenuation?: number;
+        quadraticAttenuation?: number;
+    }
+
+    export interface IGLTFLight extends IGLTFChildRootProperty {
+        type: string;
+    }
+
+    export interface IGLTFCameraOrthographic {
+        xmag: number;
+        ymag: number;
+        zfar: number;
+        znear: number;
+    }
+
+    export interface IGLTFCameraPerspective {
+        aspectRatio: number;
+        yfov: number;
+        zfar: number;
+        znear: number;
+    }
+
+    export interface IGLTFCamera extends IGLTFChildRootProperty {
+        type: string;
+    }
+
+    export interface IGLTFAnimationChannelTarget {
+        id: string;
+        path: string;
+    }
+
+    export interface IGLTFAnimationChannel {
+        sampler: string;
+        target: IGLTFAnimationChannelTarget;
+    }
+
+    export interface IGLTFAnimationSampler {
+        input: string;
+        output: string;
+
+        interpolation?: string;
+    }
+
+    export interface IGLTFAnimation extends IGLTFChildRootProperty {
+        channels?: IGLTFAnimationChannel[];
+        parameters?: Object;
+        samplers?: Object;
+    }
+
+    export interface IGLTFNodeInstanceSkin {
+        skeletons: string[];
+        skin: string;
+        meshes: string[];
+    }
+
+    export interface IGLTFSkins extends IGLTFChildRootProperty {
+        bindShapeMatrix: number[];
+        inverseBindMatrices: string;
+        jointNames: string[];
+    }
+
+    export interface IGLTFNode extends IGLTFChildRootProperty {
+        camera?: string;
+        children: string[];
+        skin?: string;
+        jointName?: string;
+        light?: string;
+        matrix: number[];
+        mesh?: string;
+        meshes?: string[];
+        rotation?: number[];
+        scale?: number[];
+        translation?: number[];
+    }
+
+    export interface IGLTFScene extends IGLTFChildRootProperty {
+        nodes: string[];
+    }
+
+    /**
+    * Runtime
+    */
+    export interface IGLTFRuntime {
+        accessors: Object;
+        buffers: Object;
+        bufferViews: Object;
+        meshes: Object;
+        lights: Object;
+        cameras: Object;
+        nodes: Object;
+        images: Object;
+        textures: Object;
+        shaders: Object;
+        programs: Object;
+        samplers: Object;
+        techniques: Object;
+        materials: Object;
+        animations: Object;
+        skins: Object;
+        currentScene: Object;
+
+        buffersCount: number;
+        shaderscount: number;
+
+        scene: Scene;
+        rootUrl: string;
+        loadedBuffers: number;
+        loadedShaders: number;
+        arrayBuffers: Object;
+
+        importOnlyMeshes: boolean;
+
+        dummyNodes: Node[];
+    }
 }

+ 73 - 64
materialsLibrary/config.json

@@ -1,65 +1,74 @@
-{
-  "materials": [
-     {
-      "file": "materials/pbr/babylon.pbrMaterial.ts",
-      "shaderFiles": [
-        "materials/pbr/pbr.vertex.fx",
-        "materials/pbr/pbr.fragment.fx",
-        "materials/pbr/legacypbr.vertex.fx",
-        "materials/pbr/legacypbr.fragment.fx"
-      ],
-      "output": "babylon.pbrMaterial.js"
-    },
-    {
-      "file": "materials/normal/babylon.normalMaterial.ts",
-      "shaderFiles": [
-        "materials/normal/normal.vertex.fx",
-        "materials/normal/normal.fragment.fx"
-      ],
-      "output": "babylon.normalMaterial.js"
-    },
-    {
-      "file": "materials/lava/babylon.lavaMaterial.ts",
-      "shaderFiles": [
-        "materials/lava/lava.vertex.fx",
-        "materials/lava/lava.fragment.fx"
-      ],
-      "output": "babylon.lavaMaterial.js"
-    },
-    {
-      "file": "materials/simple/babylon.simpleMaterial.ts",
-      "shaderFiles": [
-        "materials/simple/simple.vertex.fx",
-        "materials/simple/simple.fragment.fx"
-      ],
-      "output": "babylon.simpleMaterial.js"
-    },
-    {
-      "file": "materials/water/babylon.waterMaterial.ts",
-      "shaderFiles": [
-        "materials/water/water.vertex.fx",
-        "materials/water/water.fragment.fx"
-      ],
-      "output": "babylon.waterMaterial.js"
-    },
-    {
-      "file": "materials/fire/babylon.fireMaterial.ts",
-      "shaderFiles": [
-        "materials/fire/fire.vertex.fx",
-        "materials/fire/fire.fragment.fx"
-      ],
-      "output": "babylon.fireMaterial.js"
-    },
-    {
-      "file": "materials/terrain/babylon.terrainMaterial.ts",
-      "shaderFiles": [
-        "materials/terrain/terrain.vertex.fx",
-        "materials/terrain/terrain.fragment.fx"
-      ],
-      "output": "babylon.terrainMaterial.js"
-    }
-  ],
-  "build": {
-    "distOutputDirectory": "dist/"
-  }
+{
+  "materials": [
+     {
+      "file": "materials/pbr/babylon.pbrMaterial.ts",
+      "shaderFiles": [
+        "materials/pbr/pbr.vertex.fx",
+        "materials/pbr/pbr.fragment.fx",
+        "materials/pbr/legacypbr.vertex.fx",
+        "materials/pbr/legacypbr.fragment.fx"
+      ],
+      "output": "babylon.pbrMaterial.js"
+    },
+    {
+      "file": "materials/normal/babylon.normalMaterial.ts",
+      "shaderFiles": [
+        "materials/normal/normal.vertex.fx",
+        "materials/normal/normal.fragment.fx"
+      ],
+      "output": "babylon.normalMaterial.js"
+    },
+    {
+      "file": "materials/lava/babylon.lavaMaterial.ts",
+      "shaderFiles": [
+        "materials/lava/lava.vertex.fx",
+        "materials/lava/lava.fragment.fx"
+      ],
+      "output": "babylon.lavaMaterial.js"
+    },
+    {
+      "file": "materials/simple/babylon.simpleMaterial.ts",
+      "shaderFiles": [
+        "materials/simple/simple.vertex.fx",
+        "materials/simple/simple.fragment.fx"
+      ],
+      "output": "babylon.simpleMaterial.js"
+    },
+    {
+      "file": "materials/water/babylon.waterMaterial.ts",
+      "shaderFiles": [
+        "materials/water/water.vertex.fx",
+        "materials/water/water.fragment.fx"
+      ],
+      "output": "babylon.waterMaterial.js"
+    },
+    {
+      "file": "materials/fire/babylon.fireMaterial.ts",
+      "shaderFiles": [
+        "materials/fire/fire.vertex.fx",
+        "materials/fire/fire.fragment.fx"
+      ],
+      "output": "babylon.fireMaterial.js"
+    },
+    {
+      "file": "materials/fur/babylon.furMaterial.ts",
+      "shaderFiles": [
+        "materials/fur/fur.vertex.fx",
+        "materials/fur/fur.fragment.fx"
+      ],
+      "output": "babylon.furMaterial.js"
+    },
+    {
+      "file": "materials/terrain/babylon.terrainMaterial.ts",
+      "shaderFiles": [
+        "materials/terrain/terrain.vertex.fx",
+        "materials/terrain/terrain.fragment.fx"
+      ],
+      "output": "babylon.terrainMaterial.js"
+    }
+  ],
+  "build": {
+    "distOutputDirectory": "dist/",
+    "dtsOutputDirectory": "dist/dts/"
+  }
 }

Plik diff jest za duży
+ 43 - 2
materialsLibrary/dist/babylon.fireMaterial.js


Plik diff jest za duży
+ 1 - 1
materialsLibrary/dist/babylon.fireMaterial.min.js


Plik diff jest za duży
+ 499 - 0
materialsLibrary/dist/babylon.furMaterial.js


Plik diff jest za duży
+ 1 - 0
materialsLibrary/dist/babylon.furMaterial.min.js


Plik diff jest za duży
+ 61 - 10
materialsLibrary/dist/babylon.lavaMaterial.js


Plik diff jest za duży
+ 1 - 1
materialsLibrary/dist/babylon.lavaMaterial.min.js


Plik diff jest za duży
+ 29 - 2
materialsLibrary/dist/babylon.normalMaterial.js


Plik diff jest za duży
+ 1 - 1
materialsLibrary/dist/babylon.normalMaterial.min.js


Plik diff jest za duży
+ 140 - 4
materialsLibrary/dist/babylon.pbrMaterial.js


Plik diff jest za duży
+ 3 - 3
materialsLibrary/dist/babylon.pbrMaterial.min.js


Plik diff jest za duży
+ 29 - 2
materialsLibrary/dist/babylon.simpleMaterial.js


Plik diff jest za duży
+ 1 - 1
materialsLibrary/dist/babylon.simpleMaterial.min.js


Plik diff jest za duży
+ 66 - 2
materialsLibrary/dist/babylon.terrainMaterial.js


Plik diff jest za duży
+ 1 - 1
materialsLibrary/dist/babylon.terrainMaterial.min.js


Plik diff jest za duży
+ 51 - 2
materialsLibrary/dist/babylon.waterMaterial.js


Plik diff jest za duży
+ 1 - 1
materialsLibrary/dist/babylon.waterMaterial.min.js


+ 29 - 0
materialsLibrary/dist/dts/babylon.fireMaterial.d.ts

@@ -0,0 +1,29 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class FireMaterial extends Material {
+        diffuseTexture: BaseTexture;
+        distortionTexture: BaseTexture;
+        opacityTexture: BaseTexture;
+        diffuseColor: Color3;
+        disableLighting: boolean;
+        speed: number;
+        private _scaledDiffuse;
+        private _renderId;
+        private _defines;
+        private _cachedDefines;
+        private _lastTime;
+        constructor(name: string, scene: Scene);
+        needAlphaBlending(): boolean;
+        needAlphaTesting(): boolean;
+        getAlphaTestTexture(): BaseTexture;
+        private _checkCache(scene, mesh?, useInstances?);
+        isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean;
+        bindOnlyWorldMatrix(world: Matrix): void;
+        bind(world: Matrix, mesh?: Mesh): void;
+        getAnimatables(): IAnimatable[];
+        dispose(forceDisposeEffect?: boolean): void;
+        clone(name: string): FireMaterial;
+        serialize(): any;
+        static Parse(source: any, scene: Scene, rootUrl: string): FireMaterial;
+    }
+}

+ 30 - 0
materialsLibrary/dist/dts/babylon.furMaterial.d.ts

@@ -0,0 +1,30 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class FurMaterial extends Material {
+        diffuseTexture: BaseTexture;
+        heightTexture: BaseTexture;
+        diffuseColor: Color3;
+        furLength: number;
+        furAngle: number;
+        furColor: Color3;
+        disableLighting: boolean;
+        private _worldViewProjectionMatrix;
+        private _scaledDiffuse;
+        private _renderId;
+        private _defines;
+        private _cachedDefines;
+        constructor(name: string, scene: Scene);
+        needAlphaBlending(): boolean;
+        needAlphaTesting(): boolean;
+        getAlphaTestTexture(): BaseTexture;
+        private _checkCache(scene, mesh?, useInstances?);
+        isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean;
+        bindOnlyWorldMatrix(world: Matrix): void;
+        bind(world: Matrix, mesh?: Mesh): void;
+        getAnimatables(): IAnimatable[];
+        dispose(forceDisposeEffect?: boolean): void;
+        clone(name: string): FurMaterial;
+        serialize(): any;
+        static Parse(source: any, scene: Scene, rootUrl: string): FurMaterial;
+    }
+}

+ 33 - 0
materialsLibrary/dist/dts/babylon.lavaMaterial.d.ts

@@ -0,0 +1,33 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class LavaMaterial extends Material {
+        diffuseTexture: BaseTexture;
+        noiseTexture: BaseTexture;
+        fogColor: Color3;
+        speed: number;
+        movingSpeed: number;
+        lowFrequencySpeed: number;
+        fogDensity: number;
+        private _lastTime;
+        diffuseColor: Color3;
+        disableLighting: boolean;
+        private _worldViewProjectionMatrix;
+        private _scaledDiffuse;
+        private _renderId;
+        private _defines;
+        private _cachedDefines;
+        constructor(name: string, scene: Scene);
+        needAlphaBlending(): boolean;
+        needAlphaTesting(): boolean;
+        getAlphaTestTexture(): BaseTexture;
+        private _checkCache(scene, mesh?, useInstances?);
+        isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean;
+        bindOnlyWorldMatrix(world: Matrix): void;
+        bind(world: Matrix, mesh?: Mesh): void;
+        getAnimatables(): IAnimatable[];
+        dispose(forceDisposeEffect?: boolean): void;
+        clone(name: string): LavaMaterial;
+        serialize(): any;
+        static Parse(source: any, scene: Scene, rootUrl: string): LavaMaterial;
+    }
+}

+ 26 - 0
materialsLibrary/dist/dts/babylon.normalMaterial.d.ts

@@ -0,0 +1,26 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class NormalMaterial extends Material {
+        diffuseTexture: BaseTexture;
+        diffuseColor: Color3;
+        disableLighting: boolean;
+        private _worldViewProjectionMatrix;
+        private _scaledDiffuse;
+        private _renderId;
+        private _defines;
+        private _cachedDefines;
+        constructor(name: string, scene: Scene);
+        needAlphaBlending(): boolean;
+        needAlphaTesting(): boolean;
+        getAlphaTestTexture(): BaseTexture;
+        private _checkCache(scene, mesh?, useInstances?);
+        isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean;
+        bindOnlyWorldMatrix(world: Matrix): void;
+        bind(world: Matrix, mesh?: Mesh): void;
+        getAnimatables(): IAnimatable[];
+        dispose(forceDisposeEffect?: boolean): void;
+        clone(name: string): NormalMaterial;
+        serialize(): any;
+        static Parse(source: any, scene: Scene, rootUrl: string): NormalMaterial;
+    }
+}

+ 85 - 0
materialsLibrary/dist/dts/babylon.pbrMaterial.d.ts

@@ -0,0 +1,85 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class PBRMaterial extends BABYLON.Material {
+        directIntensity: number;
+        emissiveIntensity: number;
+        environmentIntensity: number;
+        private _lightingInfos;
+        overloadedShadowIntensity: number;
+        overloadedShadeIntensity: number;
+        private _overloadedShadowInfos;
+        cameraExposure: number;
+        cameraContrast: number;
+        private _cameraInfos;
+        overloadedAmbientIntensity: number;
+        overloadedDiffuseIntensity: number;
+        overloadedSpecularIntensity: number;
+        overloadedEmissiveIntensity: number;
+        private _overloadedIntensity;
+        overloadedAmbient: Color3;
+        overloadedDiffuse: Color3;
+        overloadedSpecular: Color3;
+        overloadedEmissive: Color3;
+        overloadedReflection: Color3;
+        overloadedGlossiness: number;
+        overloadedGlossinessIntensity: number;
+        overloadedReflectionIntensity: number;
+        private _overloadedGlossiness;
+        disableBumpMap: boolean;
+        diffuseTexture: BaseTexture;
+        ambientTexture: BaseTexture;
+        opacityTexture: BaseTexture;
+        reflectionTexture: BaseTexture;
+        emissiveTexture: BaseTexture;
+        specularTexture: BaseTexture;
+        bumpTexture: BaseTexture;
+        lightmapTexture: BaseTexture;
+        ambientColor: Color3;
+        diffuseColor: Color3;
+        specularColor: Color3;
+        reflectionColor: Color3;
+        glossiness: number;
+        emissiveColor: Color3;
+        useAlphaFromDiffuseTexture: boolean;
+        useEmissiveAsIllumination: boolean;
+        linkEmissiveWithDiffuse: boolean;
+        useSpecularOverAlpha: boolean;
+        disableLighting: boolean;
+        useLightmapAsShadowmap: boolean;
+        opacityFresnelParameters: FresnelParameters;
+        emissiveFresnelParameters: FresnelParameters;
+        useGlossinessFromSpecularMapAlpha: boolean;
+        private _renderTargets;
+        private _worldViewProjectionMatrix;
+        private _globalAmbientColor;
+        private _tempColor;
+        private _renderId;
+        private _defines;
+        private _cachedDefines;
+        private _useLogarithmicDepth;
+        constructor(name: string, scene: Scene);
+        useLogarithmicDepth: boolean;
+        needAlphaBlending(): boolean;
+        needAlphaTesting(): boolean;
+        private _shouldUseAlphaFromDiffuseTexture();
+        getAlphaTestTexture(): BaseTexture;
+        private _checkCache(scene, mesh?, useInstances?);
+        static PrepareDefinesForLights(scene: Scene, mesh: AbstractMesh, defines: MaterialDefines): boolean;
+        private static _scaledDiffuse;
+        private static _scaledSpecular;
+        private static _scaledEmissive;
+        private static _scaledReflection;
+        static BindLights(scene: Scene, mesh: AbstractMesh, effect: Effect, defines: MaterialDefines): void;
+        isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean;
+        unbind(): void;
+        bindOnlyWorldMatrix(world: Matrix): void;
+        private _myScene;
+        private _myShadowGenerator;
+        bind(world: Matrix, mesh?: Mesh): void;
+        getAnimatables(): IAnimatable[];
+        dispose(forceDisposeEffect?: boolean): void;
+        clone(name: string): PBRMaterial;
+        serialize(): any;
+        static Parse(source: any, scene: Scene, rootUrl: string): PBRMaterial;
+    }
+}

+ 26 - 0
materialsLibrary/dist/dts/babylon.simpleMaterial.d.ts

@@ -0,0 +1,26 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class SimpleMaterial extends Material {
+        diffuseTexture: BaseTexture;
+        diffuseColor: Color3;
+        disableLighting: boolean;
+        private _worldViewProjectionMatrix;
+        private _scaledDiffuse;
+        private _renderId;
+        private _defines;
+        private _cachedDefines;
+        constructor(name: string, scene: Scene);
+        needAlphaBlending(): boolean;
+        needAlphaTesting(): boolean;
+        getAlphaTestTexture(): BaseTexture;
+        private _checkCache(scene, mesh?, useInstances?);
+        isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean;
+        bindOnlyWorldMatrix(world: Matrix): void;
+        bind(world: Matrix, mesh?: Mesh): void;
+        getAnimatables(): IAnimatable[];
+        dispose(forceDisposeEffect?: boolean): void;
+        clone(name: string): SimpleMaterial;
+        serialize(): any;
+        static Parse(source: any, scene: Scene, rootUrl: string): SimpleMaterial;
+    }
+}

+ 35 - 0
materialsLibrary/dist/dts/babylon.terrainMaterial.d.ts

@@ -0,0 +1,35 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+declare module BABYLON {
+    class TerrainMaterial extends Material {
+        mixTexture: BaseTexture;
+        diffuseTexture1: Texture;
+        diffuseTexture2: Texture;
+        diffuseTexture3: Texture;
+        bumpTexture1: Texture;
+        bumpTexture2: Texture;
+        bumpTexture3: Texture;
+        diffuseColor: Color3;
+        specularColor: Color3;
+        specularPower: number;
+        disableLighting: boolean;
+        private _worldViewProjectionMatrix;
+        private _scaledDiffuse;
+        private _scaledSpecular;
+        private _renderId;
+        private _defines;
+        private _cachedDefines;
+        constructor(name: string, scene: Scene);
+        needAlphaBlending(): boolean;
+        needAlphaTesting(): boolean;
+        getAlphaTestTexture(): BaseTexture;
+        private _checkCache(scene, mesh?, useInstances?);
+        isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean;
+        bindOnlyWorldMatrix(world: Matrix): void;
+        bind(world: Matrix, mesh?: Mesh): void;
+        getAnimatables(): IAnimatable[];
+        dispose(forceDisposeEffect?: boolean): void;
+        clone(name: string): TerrainMaterial;
+        serialize(): any;
+        static Parse(source: any, scene: Scene, rootUrl: string): TerrainMaterial;
+    }
+}

+ 77 - 0
materialsLibrary/dist/dts/babylon.waterMaterial.d.ts

@@ -0,0 +1,77 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts" />
+/// <reference path="../simple/babylon.simpleMaterial.d.ts" />
+declare module BABYLON {
+    class WaterMaterial extends Material {
+        renderTargetSize: Vector2;
+        bumpTexture: BaseTexture;
+        diffuseColor: Color3;
+        specularColor: Color3;
+        specularPower: number;
+        disableLighting: boolean;
+        /**
+        * @param {number}: Represents the wind force
+        */
+        windForce: number;
+        /**
+        * @param {Vector2}: The direction of the wind in the plane (X, Z)
+        */
+        windDirection: Vector2;
+        /**
+        * @param {number}: Wave height, represents the height of the waves
+        */
+        waveHeight: number;
+        /**
+        * @param {number}: Bump height, represents the bump height related to the bump map
+        */
+        bumpHeight: number;
+        /**
+        * @param {number}: The water color blended with the reflection and refraction samplers
+        */
+        waterColor: Color3;
+        /**
+        * @param {number}: The blend factor related to the water color
+        */
+        colorBlendFactor: number;
+        /**
+        * @param {number}: Represents the maximum length of a wave
+        */
+        waveLength: number;
+        /**
+        * @param {number}: Defines the waves speed
+        */
+        waveSpeed: number;
+        private _mesh;
+        private _refractionRTT;
+        private _reflectionRTT;
+        private _material;
+        private _reflectionTransform;
+        private _lastTime;
+        private _scaledDiffuse;
+        private _scaledSpecular;
+        private _renderId;
+        private _defines;
+        private _cachedDefines;
+        /**
+        * Constructor
+        */
+        constructor(name: string, scene: Scene, renderTargetSize?: Vector2);
+        refractionTexture: RenderTargetTexture;
+        reflectionTexture: RenderTargetTexture;
+        addToRenderList(node: any): void;
+        enableRenderTargets(enable: boolean): void;
+        needAlphaBlending(): boolean;
+        needAlphaTesting(): boolean;
+        getAlphaTestTexture(): BaseTexture;
+        private _checkCache(scene, mesh?, useInstances?);
+        isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean;
+        bindOnlyWorldMatrix(world: Matrix): void;
+        bind(world: Matrix, mesh?: Mesh): void;
+        private _createRenderTargets(scene, renderTargetSize);
+        getAnimatables(): IAnimatable[];
+        dispose(forceDisposeEffect?: boolean): void;
+        clone(name: string): WaterMaterial;
+        serialize(): any;
+        static Parse(source: any, scene: Scene, rootUrl: string): WaterMaterial;
+        static CreateDefaultMesh(name: string, scene: Scene): Mesh;
+    }
+}

+ 70 - 66
materialsLibrary/gulpfile.js

@@ -1,66 +1,70 @@
-var gulp = require("gulp");
-var typescript = require("gulp-typescript");
-var srcToVariable = require("./gulp-srcToVariable");
-var merge2 = require("merge2");
-var concat = require("gulp-concat");
-var rename = require("gulp-rename");
-var cleants = require('gulp-clean-ts-extends');
-var replace = require("gulp-replace");
-var webserver = require('gulp-webserver');
-var uglify = require("gulp-uglify");
-
-var config = require("./config.json");
-var extendsSearchRegex = /var\s__extends[\s\S]+?\};/g;
-
-//function to convert the shaders' filenames to variable names.
-function shadersName(filename) {
-    return filename.replace('.fragment', 'Pixel')
-      .replace('.vertex', 'Vertex')
-      .replace('.fx', 'Shader');
-}
-
-gulp.task('copyReference', function () {
-    return gulp.src("../dist/preview release/babylon.max.js").pipe(gulp.dest("test"));
-});
-
-/*
-Compiles all typescript files and creating a declaration file.
-*/
-gulp.task('default', ["copyReference"], function () {
-    var tasks = config.materials.map(function (material) {
-        var js = gulp.src(material.file)
-            .pipe(typescript({
-                noExternalResolve: false,
-                target: 'ES5',
-                declarationFiles: true,
-                typescript: require('typescript')
-            })).js;
-
-        var shader = gulp.src(material.shaderFiles).pipe(srcToVariable("BABYLON.Effect.ShadersStore", true, shadersName));
-
-        return merge2(js, shader)
-            .pipe(cleants())
-            .pipe(replace(extendsSearchRegex, ""))
-            .pipe(concat(material.output))
-            .pipe(gulp.dest(config.build.distOutputDirectory))
-            .pipe(rename({extname: ".min.js"}))
-            .pipe(uglify())
-            .pipe(gulp.dest(config.build.distOutputDirectory));
-    });
-
-    return tasks;
-});
-
-/**
- * Web server task to serve a local test page
- */
-gulp.task('webserver', function() {
-  gulp.src('.')
-    .pipe(webserver({
-      livereload: false,
-      open: 'http://localhost:1338/test/index.html',
-      port: 1338,
-      fallback: 'index.html'
-    }));
-});
-
+var gulp = require("gulp");
+var typescript = require("gulp-typescript");
+var srcToVariable = require("./gulp-srcToVariable");
+var merge2 = require("merge2");
+var concat = require("gulp-concat");
+var rename = require("gulp-rename");
+var cleants = require('gulp-clean-ts-extends');
+var replace = require("gulp-replace");
+var webserver = require('gulp-webserver');
+var uglify = require("gulp-uglify");
+
+var config = require("./config.json");
+var extendsSearchRegex = /var\s__extends[\s\S]+?\};/g;
+
+//function to convert the shaders' filenames to variable names.
+function shadersName(filename) {
+    return filename.replace('.fragment', 'Pixel')
+      .replace('.vertex', 'Vertex')
+      .replace('.fx', 'Shader');
+}
+
+gulp.task('copyReference', function () {
+    return gulp.src("../dist/preview release/babylon.max.js").pipe(gulp.dest("test"));
+});
+
+/*
+Compiles all typescript files and creating a declaration file.
+*/
+gulp.task('default', ["copyReference"], function () {
+    var tasks = config.materials.map(function (material) {
+        var compilOutput = gulp.src(material.file)
+            .pipe(typescript({
+                noExternalResolve: false,
+                target: 'ES5',
+                declarationFiles: true,
+                typescript: require('typescript')
+            }));
+
+        var js = compilOutput.js;
+        // Build definitions file
+        var dts = compilOutput.dts.pipe(gulp.dest(config.build.dtsOutputDirectory));
+
+        var shader = gulp.src(material.shaderFiles).pipe(srcToVariable("BABYLON.Effect.ShadersStore", true, shadersName));
+
+        return merge2(js, shader)
+            .pipe(cleants())
+            .pipe(replace(extendsSearchRegex, ""))
+            .pipe(concat(material.output))
+            .pipe(gulp.dest(config.build.distOutputDirectory))
+            .pipe(rename({extname: ".min.js"}))
+            .pipe(uglify())
+            .pipe(gulp.dest(config.build.distOutputDirectory));
+    });
+
+    return tasks;
+});
+
+/**
+ * Web server task to serve a local test page
+ */
+gulp.task('webserver', function() {
+  gulp.src('.')
+    .pipe(webserver({
+      livereload: false,
+      open: 'http://localhost:1338/test/index.html',
+      port: 1338,
+      fallback: 'index.html'
+    }));
+});
+

+ 414 - 357
materialsLibrary/materials/fire/babylon.fireMaterial.ts

@@ -1,357 +1,414 @@
-/// <reference path="../../../dist/preview release/babylon.d.ts"/>
-
-module BABYLON {
-    var maxSimultaneousLights = 4;
-
-    class FireMaterialDefines extends MaterialDefines {
-        public DIFFUSE = false;
-        public CLIPPLANE = false;
-        public ALPHATEST = false;
-        public POINTSIZE = false;
-        public FOG = false;
-        public UV1 = false;
-        public NORMAL = false;
-        public VERTEXCOLOR = false;
-        public VERTEXALPHA = false;
-        public BONES = false;
-        public BONES4 = false;
-        public BonesPerMesh = 0;
-        public INSTANCES = false;
-
-        constructor() {
-            super();
-            this._keys = Object.keys(this);
-        }
-    }
-
-    export class FireMaterial extends Material {
-        public diffuseTexture: BaseTexture;
-        public distortionTexture: BaseTexture;
-        public opacityTexture: BaseTexture;
-
-        public diffuseColor = new Color3(1, 1, 1);
-        public disableLighting = false;
-        
-        public speed = 1.0;
-        
-        private _scaledDiffuse = new Color3();
-        private _renderId: number;
-
-        private _defines = new FireMaterialDefines();
-        private _cachedDefines = new FireMaterialDefines();
-        
-        private _lastTime: number = 0;
-
-        constructor(name: string, scene: Scene) {
-            super(name, scene);
-
-            this._cachedDefines.BonesPerMesh = -1;
-        }
-
-        public needAlphaBlending(): boolean {
-            return (this.alpha < 1.0);
-        }
-
-        public needAlphaTesting(): boolean {
-            return false;
-        }
-
-        public getAlphaTestTexture(): BaseTexture {
-            return null;
-        }
-
-        // Methods   
-        private _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean {
-            if (!mesh) {
-                return true;
-            }
-
-            if (this._defines.INSTANCES !== useInstances) {
-                return false;
-            }
-
-            if (mesh._materialDefines && mesh._materialDefines.isEqual(this._defines)) {
-                return true;
-            }
-
-            return false;
-        }
-
-        public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
-            if (this.checkReadyOnlyOnce) {
-                if (this._wasPreviouslyReady) {
-                    return true;
-                }
-            }
-
-            var scene = this.getScene();
-
-            if (!this.checkReadyOnEveryCall) {
-                if (this._renderId === scene.getRenderId()) {
-                    if (this._checkCache(scene, mesh, useInstances)) {
-                        return true;
-                    }
-                }
-            }
-
-            var engine = scene.getEngine();
-            var needNormals = false;
-            var needUVs = false;
-
-            this._defines.reset();
-
-            // Textures
-            if (scene.texturesEnabled) {
-                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
-                    if (!this.diffuseTexture.isReady()) {
-                        return false;
-                    } else {
-                        needUVs = true;
-                        this._defines.DIFFUSE = true;
-                    }
-                }                
-            }
-
-            // Effect
-            if (scene.clipPlane) {
-                this._defines.CLIPPLANE = true;
-            }
-            
-            this._defines.ALPHATEST = true;
-
-            // Point size
-            if (this.pointsCloud || scene.forcePointsCloud) {
-                this._defines.POINTSIZE = true;
-            }
-
-            // Fog
-            if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled) {
-                this._defines.FOG = true;
-            }
-            
-            // Attribs
-            if (mesh) {
-                if (needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
-                    this._defines.NORMAL = true;
-                }
-                if (needUVs) {
-                    if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
-                        this._defines.UV1 = true;
-                    }
-                }
-                if (mesh.useVertexColors && mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) {
-                    this._defines.VERTEXCOLOR = true;
-
-                    if (mesh.hasVertexAlpha) {
-                        this._defines.VERTEXALPHA = true;
-                    }
-                }
-                if (mesh.useBones && mesh.computeBonesUsingShaders) {
-                    this._defines.BONES = true;
-                    this._defines.BonesPerMesh = (mesh.skeleton.bones.length + 1);
-                    this._defines.BONES4 = true;
-                }
-
-                // Instances
-                if (useInstances) {
-                    this._defines.INSTANCES = true;
-                }
-            }
-
-            // Get correct effect      
-            if (!this._defines.isEqual(this._cachedDefines)) {
-                this._defines.cloneTo(this._cachedDefines);
-
-                scene.resetCachedMaterial();
-
-                // Fallbacks
-                var fallbacks = new EffectFallbacks();             
-                if (this._defines.FOG) {
-                    fallbacks.addFallback(1, "FOG");
-                }
-             
-                if (this._defines.BONES4) {
-                    fallbacks.addFallback(0, "BONES4");
-                }
-
-                //Attributes
-                var attribs = [VertexBuffer.PositionKind];
-
-                if (this._defines.NORMAL) {
-                    attribs.push(VertexBuffer.NormalKind);
-                }
-
-                if (this._defines.UV1) {
-                    attribs.push(VertexBuffer.UVKind);
-                }
-
-                if (this._defines.VERTEXCOLOR) {
-                    attribs.push(VertexBuffer.ColorKind);
-                }
-
-                if (this._defines.BONES) {
-                    attribs.push(VertexBuffer.MatricesIndicesKind);
-                    attribs.push(VertexBuffer.MatricesWeightsKind);
-                }
-
-                if (this._defines.INSTANCES) {
-                    attribs.push("world0");
-                    attribs.push("world1");
-                    attribs.push("world2");
-                    attribs.push("world3");
-                }
-
-                // Legacy browser patch
-                var shaderName = "fire";
-                
-                var join = this._defines.toString();
-                this._effect = scene.getEngine().createEffect(shaderName,
-                    attribs,
-                    ["world", "view", "viewProjection", "vEyePosition",
-                        "vFogInfos", "vFogColor", "pointSize",
-                        "vDiffuseInfos", 
-                        "mBones",
-                        "vClipPlane", "diffuseMatrix",
-                        // Fire
-                        "time", "speed"
-                    ],
-                    ["diffuseSampler",
-                        // Fire
-                        "distortionSampler", "opacitySampler"
-                    ],
-                    join, fallbacks, this.onCompiled, this.onError);
-            }
-            
-            if (!this._effect.isReady()) {
-                return false;
-            }
-
-            this._renderId = scene.getRenderId();
-            this._wasPreviouslyReady = true;
-
-            if (mesh) {
-                if (!mesh._materialDefines) {
-                    mesh._materialDefines = new FireMaterialDefines();
-                }
-
-                this._defines.cloneTo(mesh._materialDefines);
-            }
-
-            return true;
-        }
-
-        public bindOnlyWorldMatrix(world: Matrix): void {
-            this._effect.setMatrix("world", world);
-        }
-
-        public bind(world: Matrix, mesh?: Mesh): void {
-            var scene = this.getScene();
-
-            // Matrices        
-            this.bindOnlyWorldMatrix(world);
-            this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
-
-            // Bones
-            if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
-                this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
-            }
-
-            if (scene.getCachedMaterial() !== this) {
-                // Textures        
-                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
-                    this._effect.setTexture("diffuseSampler", this.diffuseTexture);
-
-                    this._effect.setFloat2("vDiffuseInfos", this.diffuseTexture.coordinatesIndex, this.diffuseTexture.level);
-                    this._effect.setMatrix("diffuseMatrix", this.diffuseTexture.getTextureMatrix());
-                    
-                    this._effect.setTexture("distortionSampler", this.distortionTexture);
-                    this._effect.setTexture("opacitySampler", this.opacityTexture);
-                }
-                
-                // Clip plane
-                if (scene.clipPlane) {
-                    var clipPlane = scene.clipPlane;
-                    this._effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
-                }
-
-                // Point size
-                if (this.pointsCloud) {
-                    this._effect.setFloat("pointSize", this.pointSize);
-                }
-
-                this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);                
-            }
-
-            this._effect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility);
-
-            // View
-            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
-                this._effect.setMatrix("view", scene.getViewMatrix());
-            }
-            
-            // Fog
-            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
-                this._effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
-                this._effect.setColor3("vFogColor", scene.fogColor);
-            }
-            
-            // Time
-            this._lastTime += scene.getEngine().getDeltaTime();
-            this._effect.setFloat("time", this._lastTime);
-            
-            // Speed
-            this._effect.setFloat("speed", this.speed);
-
-            super.bind(world, mesh);
-        }
-
-        public getAnimatables(): IAnimatable[] {
-            var results = [];
-
-            if (this.diffuseTexture && this.diffuseTexture.animations && this.diffuseTexture.animations.length > 0) {
-                results.push(this.diffuseTexture);
-            }
-            if (this.distortionTexture && this.distortionTexture.animations && this.distortionTexture.animations.length > 0) {
-                results.push(this.distortionTexture);
-            }
-            if (this.opacityTexture && this.opacityTexture.animations && this.opacityTexture.animations.length > 0) {
-                results.push(this.opacityTexture);
-            }
-
-            return results;
-        }
-
-        public dispose(forceDisposeEffect?: boolean): void {
-            if (this.diffuseTexture) {
-                this.diffuseTexture.dispose();
-            }
-            if (this.distortionTexture) {
-                this.distortionTexture.dispose();
-            }
-
-            super.dispose(forceDisposeEffect);
-        }
-
-        public clone(name: string): FireMaterial {
-            var newMaterial = new FireMaterial(name, this.getScene());
-
-            // Base material
-            this.copyTo(newMaterial);
-
-            // Fire material
-            if (this.diffuseTexture && this.diffuseTexture.clone) {
-                newMaterial.diffuseTexture = this.diffuseTexture.clone();
-            }
-            if (this.distortionTexture && this.distortionTexture.clone) {
-                newMaterial.distortionTexture = this.distortionTexture.clone();
-            }
-            if (this.opacityTexture && this.opacityTexture.clone) {
-                newMaterial.opacityTexture = this.opacityTexture.clone();
-            }
-
-            newMaterial.diffuseColor = this.diffuseColor.clone();
-            return newMaterial;
-        }
-    }
-} 
-
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON {
+    var maxSimultaneousLights = 4;
+
+    class FireMaterialDefines extends MaterialDefines {
+        public DIFFUSE = false;
+        public CLIPPLANE = false;
+        public ALPHATEST = false;
+        public POINTSIZE = false;
+        public FOG = false;
+        public UV1 = false;
+        public NORMAL = false;
+        public VERTEXCOLOR = false;
+        public VERTEXALPHA = false;
+        public BONES = false;
+        public BONES4 = false;
+        public BonesPerMesh = 0;
+        public INSTANCES = false;
+
+        constructor() {
+            super();
+            this._keys = Object.keys(this);
+        }
+    }
+
+    export class FireMaterial extends Material {
+        public diffuseTexture: BaseTexture;
+        public distortionTexture: BaseTexture;
+        public opacityTexture: BaseTexture;
+
+        public diffuseColor = new Color3(1, 1, 1);
+        public disableLighting = false;
+        
+        public speed = 1.0;
+        
+        private _scaledDiffuse = new Color3();
+        private _renderId: number;
+
+        private _defines = new FireMaterialDefines();
+        private _cachedDefines = new FireMaterialDefines();
+        
+        private _lastTime: number = 0;
+
+        constructor(name: string, scene: Scene) {
+            super(name, scene);
+
+            this._cachedDefines.BonesPerMesh = -1;
+        }
+
+        public needAlphaBlending(): boolean {
+            return (this.alpha < 1.0);
+        }
+
+        public needAlphaTesting(): boolean {
+            return false;
+        }
+
+        public getAlphaTestTexture(): BaseTexture {
+            return null;
+        }
+
+        // Methods   
+        private _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean {
+            if (!mesh) {
+                return true;
+            }
+
+            if (this._defines.INSTANCES !== useInstances) {
+                return false;
+            }
+
+            if (mesh._materialDefines && mesh._materialDefines.isEqual(this._defines)) {
+                return true;
+            }
+
+            return false;
+        }
+
+        public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
+            if (this.checkReadyOnlyOnce) {
+                if (this._wasPreviouslyReady) {
+                    return true;
+                }
+            }
+
+            var scene = this.getScene();
+
+            if (!this.checkReadyOnEveryCall) {
+                if (this._renderId === scene.getRenderId()) {
+                    if (this._checkCache(scene, mesh, useInstances)) {
+                        return true;
+                    }
+                }
+            }
+
+            var engine = scene.getEngine();
+            var needNormals = false;
+            var needUVs = false;
+
+            this._defines.reset();
+
+            // Textures
+            if (scene.texturesEnabled) {
+                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
+                    if (!this.diffuseTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.DIFFUSE = true;
+                    }
+                }                
+            }
+
+            // Effect
+            if (scene.clipPlane) {
+                this._defines.CLIPPLANE = true;
+            }
+            
+            this._defines.ALPHATEST = true;
+
+            // Point size
+            if (this.pointsCloud || scene.forcePointsCloud) {
+                this._defines.POINTSIZE = true;
+            }
+
+            // Fog
+            if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled) {
+                this._defines.FOG = true;
+            }
+            
+            // Attribs
+            if (mesh) {
+                if (needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
+                    this._defines.NORMAL = true;
+                }
+                if (needUVs) {
+                    if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                        this._defines.UV1 = true;
+                    }
+                }
+                if (mesh.useVertexColors && mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) {
+                    this._defines.VERTEXCOLOR = true;
+
+                    if (mesh.hasVertexAlpha) {
+                        this._defines.VERTEXALPHA = true;
+                    }
+                }
+                if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                    this._defines.BONES = true;
+                    this._defines.BonesPerMesh = (mesh.skeleton.bones.length + 1);
+                    this._defines.BONES4 = true;
+                }
+
+                // Instances
+                if (useInstances) {
+                    this._defines.INSTANCES = true;
+                }
+            }
+
+            // Get correct effect      
+            if (!this._defines.isEqual(this._cachedDefines)) {
+                this._defines.cloneTo(this._cachedDefines);
+
+                scene.resetCachedMaterial();
+
+                // Fallbacks
+                var fallbacks = new EffectFallbacks();             
+                if (this._defines.FOG) {
+                    fallbacks.addFallback(1, "FOG");
+                }
+             
+                if (this._defines.BONES4) {
+                    fallbacks.addFallback(0, "BONES4");
+                }
+
+                //Attributes
+                var attribs = [VertexBuffer.PositionKind];
+
+                if (this._defines.NORMAL) {
+                    attribs.push(VertexBuffer.NormalKind);
+                }
+
+                if (this._defines.UV1) {
+                    attribs.push(VertexBuffer.UVKind);
+                }
+
+                if (this._defines.VERTEXCOLOR) {
+                    attribs.push(VertexBuffer.ColorKind);
+                }
+
+                if (this._defines.BONES) {
+                    attribs.push(VertexBuffer.MatricesIndicesKind);
+                    attribs.push(VertexBuffer.MatricesWeightsKind);
+                }
+
+                if (this._defines.INSTANCES) {
+                    attribs.push("world0");
+                    attribs.push("world1");
+                    attribs.push("world2");
+                    attribs.push("world3");
+                }
+
+                // Legacy browser patch
+                var shaderName = "fire";
+                
+                var join = this._defines.toString();
+                this._effect = scene.getEngine().createEffect(shaderName,
+                    attribs,
+                    ["world", "view", "viewProjection", "vEyePosition",
+                        "vFogInfos", "vFogColor", "pointSize",
+                        "vDiffuseInfos", 
+                        "mBones",
+                        "vClipPlane", "diffuseMatrix",
+                        // Fire
+                        "time", "speed"
+                    ],
+                    ["diffuseSampler",
+                        // Fire
+                        "distortionSampler", "opacitySampler"
+                    ],
+                    join, fallbacks, this.onCompiled, this.onError);
+            }
+            
+            if (!this._effect.isReady()) {
+                return false;
+            }
+
+            this._renderId = scene.getRenderId();
+            this._wasPreviouslyReady = true;
+
+            if (mesh) {
+                if (!mesh._materialDefines) {
+                    mesh._materialDefines = new FireMaterialDefines();
+                }
+
+                this._defines.cloneTo(mesh._materialDefines);
+            }
+
+            return true;
+        }
+
+        public bindOnlyWorldMatrix(world: Matrix): void {
+            this._effect.setMatrix("world", world);
+        }
+
+        public bind(world: Matrix, mesh?: Mesh): void {
+            var scene = this.getScene();
+
+            // Matrices        
+            this.bindOnlyWorldMatrix(world);
+            this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
+
+            // Bones
+            if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
+                this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
+            }
+
+            if (scene.getCachedMaterial() !== this) {
+                // Textures        
+                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
+                    this._effect.setTexture("diffuseSampler", this.diffuseTexture);
+
+                    this._effect.setFloat2("vDiffuseInfos", this.diffuseTexture.coordinatesIndex, this.diffuseTexture.level);
+                    this._effect.setMatrix("diffuseMatrix", this.diffuseTexture.getTextureMatrix());
+                    
+                    this._effect.setTexture("distortionSampler", this.distortionTexture);
+                    this._effect.setTexture("opacitySampler", this.opacityTexture);
+                }
+                
+                // Clip plane
+                if (scene.clipPlane) {
+                    var clipPlane = scene.clipPlane;
+                    this._effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+                }
+
+                // Point size
+                if (this.pointsCloud) {
+                    this._effect.setFloat("pointSize", this.pointSize);
+                }
+
+                this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);                
+            }
+
+            this._effect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility);
+
+            // View
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
+                this._effect.setMatrix("view", scene.getViewMatrix());
+            }
+            
+            // Fog
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
+                this._effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
+                this._effect.setColor3("vFogColor", scene.fogColor);
+            }
+            
+            // Time
+            this._lastTime += scene.getEngine().getDeltaTime();
+            this._effect.setFloat("time", this._lastTime);
+            
+            // Speed
+            this._effect.setFloat("speed", this.speed);
+
+            super.bind(world, mesh);
+        }
+
+        public getAnimatables(): IAnimatable[] {
+            var results = [];
+
+            if (this.diffuseTexture && this.diffuseTexture.animations && this.diffuseTexture.animations.length > 0) {
+                results.push(this.diffuseTexture);
+            }
+            if (this.distortionTexture && this.distortionTexture.animations && this.distortionTexture.animations.length > 0) {
+                results.push(this.distortionTexture);
+            }
+            if (this.opacityTexture && this.opacityTexture.animations && this.opacityTexture.animations.length > 0) {
+                results.push(this.opacityTexture);
+            }
+
+            return results;
+        }
+
+        public dispose(forceDisposeEffect?: boolean): void {
+            if (this.diffuseTexture) {
+                this.diffuseTexture.dispose();
+            }
+            if (this.distortionTexture) {
+                this.distortionTexture.dispose();
+            }
+
+            super.dispose(forceDisposeEffect);
+        }
+
+        public clone(name: string): FireMaterial {
+            var newMaterial = new FireMaterial(name, this.getScene());
+
+            // Base material
+            this.copyTo(newMaterial);
+
+            // Fire material
+            if (this.diffuseTexture && this.diffuseTexture.clone) {
+                newMaterial.diffuseTexture = this.diffuseTexture.clone();
+            }
+            if (this.distortionTexture && this.distortionTexture.clone) {
+                newMaterial.distortionTexture = this.distortionTexture.clone();
+            }
+            if (this.opacityTexture && this.opacityTexture.clone) {
+                newMaterial.opacityTexture = this.opacityTexture.clone();
+            }
+
+            newMaterial.diffuseColor = this.diffuseColor.clone();
+            return newMaterial;
+        }
+		
+		public serialize(): any {
+		
+            var serializationObject = super.serialize();
+            serializationObject.customType      = "BABYLON.FireMaterial";
+            serializationObject.diffuseColor    = this.diffuseColor.asArray();
+            serializationObject.speed           = this.speed;
+            serializationObject.disableLighting = this.disableLighting;
+
+            if (this.diffuseTexture) {
+                serializationObject.diffuseTexture = this.diffuseTexture.serialize();
+            }
+            
+			if (this.distortionTexture) {
+                serializationObject.distortionTexture = this.distortionTexture.serialize();
+            }
+			
+			if (this.opacityTexture) {
+                serializationObject.opacityTexture = this.opacityTexture.serialize();
+            }
+
+            return serializationObject;
+        }
+
+        public static Parse(source: any, scene: Scene, rootUrl: string): FireMaterial {
+            var material = new FireMaterial(source.name, scene);
+
+            material.diffuseColor   = Color3.FromArray(source.diffuseColor);
+            material.speed          = source.speed;
+            material.disableLighting    = source.disableLighting;
+
+            material.alpha          = source.alpha;
+
+            material.id             = source.id;
+
+            Tags.AddTagsTo(material, source.tags);
+            material.backFaceCulling = source.backFaceCulling;
+            material.wireframe = source.wireframe;
+
+            if (source.diffuseTexture) {
+                material.diffuseTexture = Texture.Parse(source.diffuseTexture, scene, rootUrl);
+            }
+
+            if (source.distortionTexture) {
+                material.distortionTexture = Texture.Parse(source.distortionTexture, scene, rootUrl);
+            }
+			
+			if (source.opacityTexture) {
+                material.opacityTexture = Texture.Parse(source.opacityTexture, scene, rootUrl);
+            }
+
+            if (source.checkReadyOnlyOnce) {
+                material.checkReadyOnlyOnce = source.checkReadyOnlyOnce;
+            }
+
+            return material;
+        }
+    }
+} 
+

+ 601 - 0
materialsLibrary/materials/fur/babylon.furMaterial.ts

@@ -0,0 +1,601 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON {
+    var maxSimultaneousLights = 4;
+
+    class FurMaterialDefines extends MaterialDefines {
+        public DIFFUSE = false;
+        public HEIGHTMAP = false;
+        public CLIPPLANE = false;
+        public ALPHATEST = false;
+        public POINTSIZE = false;
+        public FOG = false;
+        public LIGHT0 = false;
+        public LIGHT1 = false;
+        public LIGHT2 = false;
+        public LIGHT3 = false;
+        public SPOTLIGHT0 = false;
+        public SPOTLIGHT1 = false;
+        public SPOTLIGHT2 = false;
+        public SPOTLIGHT3 = false;
+        public HEMILIGHT0 = false;
+        public HEMILIGHT1 = false;
+        public HEMILIGHT2 = false;
+        public HEMILIGHT3 = false;
+        public DIRLIGHT0 = false;
+        public DIRLIGHT1 = false;
+        public DIRLIGHT2 = false;
+        public DIRLIGHT3 = false;
+        public POINTLIGHT0 = false;
+        public POINTLIGHT1 = false;
+        public POINTLIGHT2 = false;
+        public POINTLIGHT3 = false;        
+        public SHADOW0 = false;
+        public SHADOW1 = false;
+        public SHADOW2 = false;
+        public SHADOW3 = false;
+        public SHADOWS = false;
+        public SHADOWVSM0 = false;
+        public SHADOWVSM1 = false;
+        public SHADOWVSM2 = false;
+        public SHADOWVSM3 = false;
+        public SHADOWPCF0 = false;
+        public SHADOWPCF1 = false;
+        public SHADOWPCF2 = false;
+        public SHADOWPCF3 = false;
+        public NORMAL = false;
+        public UV1 = false;
+        public UV2 = false;
+        public VERTEXCOLOR = false;
+        public VERTEXALPHA = false;
+        public BONES = false;
+        public BONES4 = false;
+        public BonesPerMesh = 0;
+        public INSTANCES = false;
+
+        constructor() {
+            super();
+            this._keys = Object.keys(this);
+        }
+    }
+
+    export class FurMaterial extends Material {
+        public diffuseTexture: BaseTexture;
+        public heightTexture: BaseTexture;
+        public diffuseColor = new Color3(1, 1, 1);
+        public furLength: number = 1;
+        public furAngle: number = 0;
+        public furColor = new Color3(0.44,0.21,0.02);
+        public disableLighting = false;
+
+        private _worldViewProjectionMatrix = Matrix.Zero();
+        private _scaledDiffuse = new Color3(1.,1.,1.);
+        private _renderId: number;
+
+        private _defines = new FurMaterialDefines();
+        private _cachedDefines = new FurMaterialDefines();
+
+        constructor(name: string, scene: Scene) {
+            super(name, scene);
+
+            this._cachedDefines.BonesPerMesh = -1;
+        }
+
+        public needAlphaBlending(): boolean {
+            return (this.alpha < 1.0);
+        }
+
+        public needAlphaTesting(): boolean {
+            return false;
+        }
+
+        public getAlphaTestTexture(): BaseTexture {
+            return null;
+        }
+
+        // Methods   
+        private _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean {
+            if (!mesh) {
+                return true;
+            }
+
+            if (this._defines.INSTANCES !== useInstances) {
+                return false;
+            }
+
+            if (mesh._materialDefines && mesh._materialDefines.isEqual(this._defines)) {
+                return true;
+            }
+
+            return false;
+        }
+
+        public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
+            if (this.checkReadyOnlyOnce) {
+                if (this._wasPreviouslyReady) {
+                    return true;
+                }
+            }
+
+            var scene = this.getScene();
+
+            if (!this.checkReadyOnEveryCall) {
+                if (this._renderId === scene.getRenderId()) {
+                    if (this._checkCache(scene, mesh, useInstances)) {
+                        return true;
+                    }
+                }
+            }
+
+            var engine = scene.getEngine();
+            var needNormals = false;
+            var needUVs = false;
+
+            this._defines.reset();
+
+            // Textures
+            if (scene.texturesEnabled) {
+                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
+                    if (!this.diffuseTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.DIFFUSE = true;
+                    }
+                } 
+                if (this.heightTexture) {
+                    if (!this.heightTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.HEIGHTMAP = true;
+                    }
+                }               
+            }
+
+            // Effect
+            if (scene.clipPlane) {
+                this._defines.CLIPPLANE = true;
+            }
+
+            if (engine.getAlphaTesting()) {
+                this._defines.ALPHATEST = true;
+            }
+
+            // Point size
+            if (this.pointsCloud || scene.forcePointsCloud) {
+                this._defines.POINTSIZE = true;
+            }
+
+            // Fog
+            if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled) {
+                this._defines.FOG = true;
+            }
+
+            var lightIndex = 0;
+            if (scene.lightsEnabled && !this.disableLighting) {
+                for (var index = 0; index < scene.lights.length; index++) {
+                    var light = scene.lights[index];
+
+                    if (!light.isEnabled()) {
+                        continue;
+                    }
+
+                    // Excluded check
+                    if (light._excludedMeshesIds.length > 0) {
+                        for (var excludedIndex = 0; excludedIndex < light._excludedMeshesIds.length; excludedIndex++) {
+                            var excludedMesh = scene.getMeshByID(light._excludedMeshesIds[excludedIndex]);
+
+                            if (excludedMesh) {
+                                light.excludedMeshes.push(excludedMesh);
+                            }
+                        }
+
+                        light._excludedMeshesIds = [];
+                    }
+
+                    // Included check
+                    if (light._includedOnlyMeshesIds.length > 0) {
+                        for (var includedOnlyIndex = 0; includedOnlyIndex < light._includedOnlyMeshesIds.length; includedOnlyIndex++) {
+                            var includedOnlyMesh = scene.getMeshByID(light._includedOnlyMeshesIds[includedOnlyIndex]);
+
+                            if (includedOnlyMesh) {
+                                light.includedOnlyMeshes.push(includedOnlyMesh);
+                            }
+                        }
+
+                        light._includedOnlyMeshesIds = [];
+                    }
+
+                    if (!light.canAffectMesh(mesh)) {
+                        continue;
+                    }
+                    needNormals = true;
+                    this._defines["LIGHT" + lightIndex] = true;
+
+                    var type;
+                    if (light instanceof SpotLight) {
+                        type = "SPOTLIGHT" + lightIndex;
+                    } else if (light instanceof HemisphericLight) {
+                        type = "HEMILIGHT" + lightIndex;
+                    } else if (light instanceof PointLight) {
+                        type = "POINTLIGHT" + lightIndex;
+                    } else {
+                        type = "DIRLIGHT" + lightIndex;
+                    }
+
+                    this._defines[type] = true;
+
+                    // Shadows
+                    if (scene.shadowsEnabled) {
+                        var shadowGenerator = light.getShadowGenerator();
+                        if (mesh && mesh.receiveShadows && shadowGenerator) {
+                            this._defines["SHADOW" + lightIndex] = true;
+
+                            this._defines.SHADOWS = true;
+
+                            if (shadowGenerator.useVarianceShadowMap || shadowGenerator.useBlurVarianceShadowMap) {
+                                this._defines["SHADOWVSM" + lightIndex] = true;
+                            }
+
+                            if (shadowGenerator.usePoissonSampling) {
+                                this._defines["SHADOWPCF" + lightIndex] = true;
+                            }
+                        }
+                    }
+
+                    lightIndex++;
+                    if (lightIndex === maxSimultaneousLights)
+                        break;
+                }
+            }
+
+            // Attribs
+            if (mesh) {
+                if (needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
+                    this._defines.NORMAL = true;
+                }
+                if (needUVs) {
+                    if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                        this._defines.UV1 = true;
+                    }
+                    if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
+                        this._defines.UV2 = true;
+                    }
+                }
+                if (mesh.useVertexColors && mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) {
+                    this._defines.VERTEXCOLOR = true;
+
+                    if (mesh.hasVertexAlpha) {
+                        this._defines.VERTEXALPHA = true;
+                    }
+                }
+                if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                    this._defines.BONES = true;
+                    this._defines.BonesPerMesh = (mesh.skeleton.bones.length + 1);
+                    this._defines.BONES4 = true;
+                }
+
+                // Instances
+                if (useInstances) {
+                    this._defines.INSTANCES = true;
+                }
+            }
+
+            // Get correct effect      
+            if (!this._defines.isEqual(this._cachedDefines)) {
+                this._defines.cloneTo(this._cachedDefines);
+
+                scene.resetCachedMaterial();
+
+                // Fallbacks
+                var fallbacks = new EffectFallbacks();             
+                if (this._defines.FOG) {
+                    fallbacks.addFallback(1, "FOG");
+                }
+
+                for (lightIndex = 0; lightIndex < maxSimultaneousLights; lightIndex++) {
+                    if (!this._defines["LIGHT" + lightIndex]) {
+                        continue;
+                    }
+
+                    if (lightIndex > 0) {
+                        fallbacks.addFallback(lightIndex, "LIGHT" + lightIndex);
+                    }
+
+                    if (this._defines["SHADOW" + lightIndex]) {
+                        fallbacks.addFallback(0, "SHADOW" + lightIndex);
+                    }
+
+                    if (this._defines["SHADOWPCF" + lightIndex]) {
+                        fallbacks.addFallback(0, "SHADOWPCF" + lightIndex);
+                    }
+
+                    if (this._defines["SHADOWVSM" + lightIndex]) {
+                        fallbacks.addFallback(0, "SHADOWVSM" + lightIndex);
+                    }
+                }
+             
+                if (this._defines.BONES4) {
+                    fallbacks.addFallback(0, "BONES4");
+                }
+
+                //Attributes
+                var attribs = [VertexBuffer.PositionKind];
+
+                if (this._defines.NORMAL) {
+                    attribs.push(VertexBuffer.NormalKind);
+                }
+
+                if (this._defines.UV1) {
+                    attribs.push(VertexBuffer.UVKind);
+                }
+
+                if (this._defines.UV2) {
+                    attribs.push(VertexBuffer.UV2Kind);
+                }
+
+                if (this._defines.VERTEXCOLOR) {
+                    attribs.push(VertexBuffer.ColorKind);
+                }
+
+                if (this._defines.BONES) {
+                    attribs.push(VertexBuffer.MatricesIndicesKind);
+                    attribs.push(VertexBuffer.MatricesWeightsKind);
+                }
+
+                if (this._defines.INSTANCES) {
+                    attribs.push("world0");
+                    attribs.push("world1");
+                    attribs.push("world2");
+                    attribs.push("world3");
+                }
+
+                // Legacy browser patch
+                var shaderName = "fur";
+                var join = this._defines.toString();
+                this._effect = scene.getEngine().createEffect(shaderName,
+                    attribs,
+                    ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vDiffuseColor",
+                        "vLightData0", "vLightDiffuse0", "vLightSpecular0", "vLightDirection0", "vLightGround0", "lightMatrix0",
+                        "vLightData1", "vLightDiffuse1", "vLightSpecular1", "vLightDirection1", "vLightGround1", "lightMatrix1",
+                        "vLightData2", "vLightDiffuse2", "vLightSpecular2", "vLightDirection2", "vLightGround2", "lightMatrix2",
+                        "vLightData3", "vLightDiffuse3", "vLightSpecular3", "vLightDirection3", "vLightGround3", "lightMatrix3",
+                        "vFogInfos", "vFogColor", "pointSize",
+                        "vDiffuseInfos", 
+                        "mBones",
+                        "vClipPlane", "diffuseMatrix",
+                        "shadowsInfo0", "shadowsInfo1", "shadowsInfo2", "shadowsInfo3",
+                        "furLength", "furAngle", "furColor"
+                    ],
+                    ["diffuseSampler",
+                        "shadowSampler0", "shadowSampler1", "shadowSampler2", "shadowSampler3",
+                        "heightTexture"
+                    ],
+                    join, fallbacks, this.onCompiled, this.onError);
+            }
+            if (!this._effect.isReady()) {
+                return false;
+            }
+
+            this._renderId = scene.getRenderId();
+            this._wasPreviouslyReady = true;
+
+            if (mesh) {
+                if (!mesh._materialDefines) {
+                    mesh._materialDefines = new FurMaterialDefines();
+                }
+
+                this._defines.cloneTo(mesh._materialDefines);
+            }
+
+            return true;
+        }
+
+        public bindOnlyWorldMatrix(world: Matrix): void {
+            this._effect.setMatrix("world", world);
+        }
+
+        public bind(world: Matrix, mesh?: Mesh): void {
+            var scene = this.getScene();
+
+            // Matrices        
+            this.bindOnlyWorldMatrix(world);
+            this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
+
+            // Bones
+            if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
+                this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
+            }
+
+            if (scene.getCachedMaterial() !== this) {
+                // Textures        
+                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
+                    this._effect.setTexture("diffuseSampler", this.diffuseTexture);
+
+                    this._effect.setFloat2("vDiffuseInfos", this.diffuseTexture.coordinatesIndex, this.diffuseTexture.level);
+                    this._effect.setMatrix("diffuseMatrix", this.diffuseTexture.getTextureMatrix());
+                }
+                
+                if (this.heightTexture) {
+                    this._effect.setTexture("heightTexture", this.heightTexture);
+                }
+                
+                // Clip plane
+                if (scene.clipPlane) {
+                    var clipPlane = scene.clipPlane;
+                    this._effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+                }
+
+                // Point size
+                if (this.pointsCloud) {
+                    this._effect.setFloat("pointSize", this.pointSize);
+                }
+
+                this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);                
+            }
+
+            this._effect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility);
+
+            if (scene.lightsEnabled && !this.disableLighting) {
+                var lightIndex = 0;
+                for (var index = 0; index < scene.lights.length; index++) {
+                    var light = scene.lights[index];
+
+                    if (!light.isEnabled()) {
+                        continue;
+                    }
+
+                    if (!light.canAffectMesh(mesh)) {
+                        continue;
+                    }
+
+                    if (light instanceof PointLight) {
+                        // Point Light
+                        light.transferToEffect(this._effect, "vLightData" + lightIndex);
+                    } else if (light instanceof DirectionalLight) {
+                        // Directional Light
+                        light.transferToEffect(this._effect, "vLightData" + lightIndex);
+                    } else if (light instanceof SpotLight) {
+                        // Spot Light
+                        light.transferToEffect(this._effect, "vLightData" + lightIndex, "vLightDirection" + lightIndex);
+                    } else if (light instanceof HemisphericLight) {
+                        // Hemispheric Light
+                        light.transferToEffect(this._effect, "vLightData" + lightIndex, "vLightGround" + lightIndex);
+                    }
+
+                    light.diffuse.scaleToRef(light.intensity, this._scaledDiffuse);
+                    this._effect.setColor4("vLightDiffuse" + lightIndex, this._scaledDiffuse, light.range);
+
+                    // Shadows
+                    if (scene.shadowsEnabled) {
+                        var shadowGenerator = light.getShadowGenerator();
+                        if (mesh.receiveShadows && shadowGenerator) {
+                            this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix());
+                            this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMapForRendering());
+                            this._effect.setFloat3("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.getShadowMap().getSize().width, shadowGenerator.bias);
+                        }
+                    }
+
+                    lightIndex++;
+
+                    if (lightIndex === maxSimultaneousLights)
+                        break;
+                }
+            }
+
+            // View
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
+                this._effect.setMatrix("view", scene.getViewMatrix());
+            }
+
+            // Fog
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
+                this._effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
+                this._effect.setColor3("vFogColor", scene.fogColor);
+            }
+            
+            this._effect.setFloat("furLength", this.furLength);
+            this._effect.setFloat("furAngle", this.furAngle);
+            this._effect.setColor4("furColor", this.furColor, 1.0);
+
+ 
+            super.bind(world, mesh);
+        }
+
+        public getAnimatables(): IAnimatable[] {
+            var results = [];
+
+            if (this.diffuseTexture && this.diffuseTexture.animations && this.diffuseTexture.animations.length > 0) {
+                results.push(this.diffuseTexture);
+            }
+            
+            if (this.heightTexture && this.heightTexture.animations && this.heightTexture.animations.length > 0) {
+                results.push(this.heightTexture);
+            }
+
+            return results;
+        }
+
+        public dispose(forceDisposeEffect?: boolean): void {
+            if (this.diffuseTexture) {
+                this.diffuseTexture.dispose();
+            }
+
+            super.dispose(forceDisposeEffect);
+        }
+
+        public clone(name: string): FurMaterial {
+            var newMaterial = new FurMaterial(name, this.getScene());
+
+            // Base material
+            this.copyTo(newMaterial);
+
+            // Fur material
+            if (this.diffuseTexture && this.diffuseTexture.clone) {
+                newMaterial.diffuseTexture = this.diffuseTexture.clone();
+            }
+            if (this.heightTexture && this.heightTexture.clone) {
+                newMaterial.heightTexture = this.heightTexture.clone();
+            }
+            if (this.diffuseColor && this.diffuseColor.clone) {
+                newMaterial.diffuseColor = this.diffuseColor.clone();
+            }
+            
+            return newMaterial;
+        }
+        
+        public serialize(): any {		
+            var serializationObject = super.serialize();
+            serializationObject.customType      = "BABYLON.FurMaterial";
+            serializationObject.diffuseColor    = this.diffuseColor.asArray();
+            serializationObject.disableLighting = this.disableLighting;
+            serializationObject.furLength = this.furLength;
+            serializationObject.furAngle = this.furAngle;
+            serializationObject.furColor = this.furColor.asArray();
+            
+            if (this.diffuseTexture) {
+                serializationObject.diffuseTexture = this.diffuseTexture.serialize();
+            }
+            
+            if (this.heightTexture) {
+                serializationObject.heightTexture = this.heightTexture.serialize();
+            }
+
+            return serializationObject;
+        }
+
+        public static Parse(source: any, scene: Scene, rootUrl: string): FurMaterial {
+            var material = new FurMaterial(source.name, scene);
+
+            material.diffuseColor       = Color3.FromArray(source.diffuseColor);
+            material.furLength          = source.furLength;
+            material.furAngle           = source.furAngle;
+            material.furColor           = Color3.FromArray(source.furColor);
+            material.disableLighting    = source.disableLighting;
+
+            material.alpha          = source.alpha;
+
+            material.id             = source.id;
+
+            Tags.AddTagsTo(material, source.tags);
+            material.backFaceCulling = source.backFaceCulling;
+            material.wireframe = source.wireframe;
+
+            if (source.diffuseTexture) {
+                material.diffuseTexture = Texture.Parse(source.diffuseTexture, scene, rootUrl);
+            }
+            
+            if (source.heightTexture) {
+                material.heightTexture = Texture.Parse(source.heightTexture, scene, rootUrl);
+            }
+
+            if (source.checkReadyOnlyOnce) {
+                material.checkReadyOnlyOnce = source.checkReadyOnlyOnce;
+            }
+
+            return material;
+        }
+    }
+} 
+

+ 565 - 0
materialsLibrary/materials/fur/fur.fragment.fx

@@ -0,0 +1,565 @@
+precision highp float;
+
+// Constants
+uniform vec3 vEyePosition;
+uniform vec4 vDiffuseColor;
+
+// Input
+uniform vec4 furColor;
+varying vec3 vPositionW;
+varying float vfur_length;
+
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+// Lights
+#ifdef LIGHT0
+uniform vec4 vLightData0;
+uniform vec4 vLightDiffuse0;
+#ifdef SHADOW0
+#if defined(SPOTLIGHT0) || defined(DIRLIGHT0)
+varying vec4 vPositionFromLight0;
+uniform sampler2D shadowSampler0;
+#else
+uniform samplerCube shadowSampler0;
+#endif
+uniform vec3 shadowsInfo0;
+#endif
+#ifdef SPOTLIGHT0
+uniform vec4 vLightDirection0;
+#endif
+#ifdef HEMILIGHT0
+uniform vec3 vLightGround0;
+#endif
+#endif
+
+#ifdef LIGHT1
+uniform vec4 vLightData1;
+uniform vec4 vLightDiffuse1;
+#ifdef SHADOW1
+#if defined(SPOTLIGHT1) || defined(DIRLIGHT1)
+varying vec4 vPositionFromLight1;
+uniform sampler2D shadowSampler1;
+#else
+uniform samplerCube shadowSampler1;
+#endif
+uniform vec3 shadowsInfo1;
+#endif
+#ifdef SPOTLIGHT1
+uniform vec4 vLightDirection1;
+#endif
+#ifdef HEMILIGHT1
+uniform vec3 vLightGround1;
+#endif
+#endif
+
+#ifdef LIGHT2
+uniform vec4 vLightData2;
+uniform vec4 vLightDiffuse2;
+#ifdef SHADOW2
+#if defined(SPOTLIGHT2) || defined(DIRLIGHT2)
+varying vec4 vPositionFromLight2;
+uniform sampler2D shadowSampler2;
+#else
+uniform samplerCube shadowSampler2;
+#endif
+uniform vec3 shadowsInfo2;
+#endif
+#ifdef SPOTLIGHT2
+uniform vec4 vLightDirection2;
+#endif
+#ifdef HEMILIGHT2
+uniform vec3 vLightGround2;
+#endif
+#endif
+
+#ifdef LIGHT3
+uniform vec4 vLightData3;
+uniform vec4 vLightDiffuse3;
+#ifdef SHADOW3
+#if defined(SPOTLIGHT3) || defined(DIRLIGHT3)
+varying vec4 vPositionFromLight3;
+uniform sampler2D shadowSampler3;
+#else
+uniform samplerCube shadowSampler3;
+#endif
+uniform vec3 shadowsInfo3;
+#endif
+#ifdef SPOTLIGHT3
+uniform vec4 vLightDirection3;
+#endif
+#ifdef HEMILIGHT3
+uniform vec3 vLightGround3;
+#endif
+#endif
+
+// Samplers
+#ifdef DIFFUSE
+varying vec2 vDiffuseUV;
+uniform sampler2D diffuseSampler;
+uniform vec2 vDiffuseInfos;
+#endif
+
+// Shadows
+#ifdef SHADOWS
+
+float unpack(vec4 color)
+{
+	const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
+	return dot(color, bit_shift);
+}
+
+#if defined(POINTLIGHT0) || defined(POINTLIGHT1) || defined(POINTLIGHT2) || defined(POINTLIGHT3)
+float computeShadowCube(vec3 lightPosition, samplerCube shadowSampler, float darkness, float bias)
+{
+	vec3 directionToLight = vPositionW - lightPosition;
+	float depth = length(directionToLight);
+
+	depth = clamp(depth, 0., 1.);
+
+	directionToLight.y = 1.0 - directionToLight.y;
+
+	float shadow = unpack(textureCube(shadowSampler, directionToLight)) + bias;
+
+	if (depth > shadow)
+	{
+		return darkness;
+	}
+	return 1.0;
+}
+
+float computeShadowWithPCFCube(vec3 lightPosition, samplerCube shadowSampler, float bias, float darkness)
+{
+	vec3 directionToLight = vPositionW - lightPosition;
+	float depth = length(directionToLight);
+
+	depth = clamp(depth, 0., 1.);
+
+	directionToLight.y = 1.0 - directionToLight.y;
+
+	float visibility = 1.;
+
+	vec3 poissonDisk[4];
+	poissonDisk[0] = vec3(-0.094201624, 0.04, -0.039906216);
+	poissonDisk[1] = vec3(0.094558609, -0.04, -0.076890725);
+	poissonDisk[2] = vec3(-0.094184101, 0.01, -0.092938870);
+	poissonDisk[3] = vec3(0.034495938, -0.01, 0.029387760);
+
+	// Poisson Sampling
+	float biasedDepth = depth - bias;
+
+	if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[0])) < biasedDepth) visibility -= 0.25;
+	if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[1])) < biasedDepth) visibility -= 0.25;
+	if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[2])) < biasedDepth) visibility -= 0.25;
+	if (unpack(textureCube(shadowSampler, directionToLight + poissonDisk[3])) < biasedDepth) visibility -= 0.25;
+
+	return  min(1.0, visibility + darkness);
+}
+#endif
+
+#if defined(SPOTLIGHT0) || defined(SPOTLIGHT1) || defined(SPOTLIGHT2) || defined(SPOTLIGHT3) ||  defined(DIRLIGHT0) || defined(DIRLIGHT1) || defined(DIRLIGHT2) || defined(DIRLIGHT3)
+float computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler, float darkness, float bias)
+{
+	vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
+	depth = 0.5 * depth + vec3(0.5);
+	vec2 uv = depth.xy;
+
+	if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
+	{
+		return 1.0;
+	}
+
+	float shadow = unpack(texture2D(shadowSampler, uv)) + bias;
+
+	if (depth.z > shadow)
+	{
+		return darkness;
+	}
+	return 1.;
+}
+
+float computeShadowWithPCF(vec4 vPositionFromLight, sampler2D shadowSampler, float mapSize, float bias, float darkness)
+{
+	vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
+	depth = 0.5 * depth + vec3(0.5);
+	vec2 uv = depth.xy;
+
+	if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
+	{
+		return 1.0;
+	}
+
+	float visibility = 1.;
+
+	vec2 poissonDisk[4];
+	poissonDisk[0] = vec2(-0.94201624, -0.39906216);
+	poissonDisk[1] = vec2(0.94558609, -0.76890725);
+	poissonDisk[2] = vec2(-0.094184101, -0.92938870);
+	poissonDisk[3] = vec2(0.34495938, 0.29387760);
+
+	// Poisson Sampling
+	float biasedDepth = depth.z - bias;
+
+	if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] / mapSize)) < biasedDepth) visibility -= 0.25;
+	if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] / mapSize)) < biasedDepth) visibility -= 0.25;
+	if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] / mapSize)) < biasedDepth) visibility -= 0.25;
+	if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] / mapSize)) < biasedDepth) visibility -= 0.25;
+
+	return  min(1.0, visibility + darkness);
+}
+
+// Thanks to http://devmaster.net/
+float unpackHalf(vec2 color)
+{
+	return color.x + (color.y / 255.0);
+}
+
+float linstep(float low, float high, float v) {
+	return clamp((v - low) / (high - low), 0.0, 1.0);
+}
+
+float ChebychevInequality(vec2 moments, float compare, float bias)
+{
+	float p = smoothstep(compare - bias, compare, moments.x);
+	float variance = max(moments.y - moments.x * moments.x, 0.02);
+	float d = compare - moments.x;
+	float p_max = linstep(0.2, 1.0, variance / (variance + d * d));
+
+	return clamp(max(p, p_max), 0.0, 1.0);
+}
+
+float computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler, float bias, float darkness)
+{
+	vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
+	depth = 0.5 * depth + vec3(0.5);
+	vec2 uv = depth.xy;
+
+	if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0 || depth.z >= 1.0)
+	{
+		return 1.0;
+	}
+
+	vec4 texel = texture2D(shadowSampler, uv);
+
+	vec2 moments = vec2(unpackHalf(texel.xy), unpackHalf(texel.zw));
+	return min(1.0, 1.0 - ChebychevInequality(moments, depth.z, bias) + darkness);
+}
+#endif
+#endif
+
+
+#ifdef CLIPPLANE
+varying float fClipDistance;
+#endif
+
+// Fog
+#ifdef FOG
+
+#define FOGMODE_NONE    0.
+#define FOGMODE_EXP     1.
+#define FOGMODE_EXP2    2.
+#define FOGMODE_LINEAR  3.
+#define E 2.71828
+
+uniform vec4 vFogInfos;
+uniform vec3 vFogColor;
+varying float fFogDistance;
+
+float CalcFogFactor()
+{
+	float fogCoeff = 1.0;
+	float fogStart = vFogInfos.y;
+	float fogEnd = vFogInfos.z;
+	float fogDensity = vFogInfos.w;
+
+	if (FOGMODE_LINEAR == vFogInfos.x)
+	{
+		fogCoeff = (fogEnd - fFogDistance) / (fogEnd - fogStart);
+	}
+	else if (FOGMODE_EXP == vFogInfos.x)
+	{
+		fogCoeff = 1.0 / pow(E, fFogDistance * fogDensity);
+	}
+	else if (FOGMODE_EXP2 == vFogInfos.x)
+	{
+		fogCoeff = 1.0 / pow(E, fFogDistance * fFogDistance * fogDensity * fogDensity);
+	}
+
+	return clamp(fogCoeff, 0.0, 1.0);
+}
+#endif
+
+// Light Computing
+struct lightingInfo
+{
+	vec3 diffuse;
+};
+
+lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, float range) {
+	lightingInfo result;
+
+	vec3 lightVectorW;
+	float attenuation = 1.0;
+	if (lightData.w == 0.)
+	{
+		vec3 direction = lightData.xyz - vPositionW;
+
+		attenuation = max(0., 1.0 - length(direction) / range);
+		lightVectorW = normalize(direction);
+	}
+	else
+	{
+		lightVectorW = normalize(-lightData.xyz);
+	}
+
+	// diffuse
+	float ndl = max(0., dot(vNormal, lightVectorW));
+	result.diffuse = ndl * diffuseColor * attenuation;
+
+	return result;
+}
+
+lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, float range) {
+	lightingInfo result;
+
+	vec3 direction = lightData.xyz - vPositionW;
+	vec3 lightVectorW = normalize(direction);
+	float attenuation = max(0., 1.0 - length(direction) / range);
+
+	// diffuse
+	float cosAngle = max(0., dot(-lightDirection.xyz, lightVectorW));
+	float spotAtten = 0.0;
+
+	if (cosAngle >= lightDirection.w)
+	{
+		cosAngle = max(0., pow(cosAngle, lightData.w));
+		spotAtten = clamp((cosAngle - lightDirection.w) / (1. - cosAngle), 0.0, 1.0);
+
+		// Diffuse
+		float ndl = max(0., dot(vNormal, -lightDirection.xyz));
+		result.diffuse = ndl * spotAtten * diffuseColor * attenuation;
+
+		return result;
+	}
+
+	result.diffuse = vec3(0.);
+
+	return result;
+}
+
+lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 groundColor) {
+	lightingInfo result;
+
+	// Diffuse
+	float ndl = dot(vNormal, lightData.xyz) * 0.5 + 0.5;
+	result.diffuse = mix(groundColor, diffuseColor, ndl);
+
+	return result;
+}
+
+float Rand(vec3 rv) {
+	float x = dot(rv, vec3(12.9898,78.233, 24.65487));
+	return fract(sin(x) * 43758.5453);
+}
+
+void main(void) {
+	// Clip plane
+#ifdef CLIPPLANE
+	if (fClipDistance > 0.0)
+		discard;
+#endif
+
+	vec3 viewDirectionW = normalize(vEyePosition - vPositionW);
+
+	// Base color
+	vec4 baseColor = furColor;
+	vec3 diffuseColor = vDiffuseColor.rgb;
+
+	// Alpha
+	float alpha = vDiffuseColor.a;
+
+#ifdef DIFFUSE
+	baseColor = texture2D(diffuseSampler, vDiffuseUV);
+
+#ifdef ALPHATEST
+	if (baseColor.a < 0.4)
+		discard;
+#endif
+
+	baseColor.rgb *= vDiffuseInfos.y;
+#endif
+
+#ifdef VERTEXCOLOR
+	baseColor.rgb *= vColor.rgb;
+#endif
+
+	// Bump
+#ifdef NORMAL
+	vec3 normalW = normalize(vNormalW);
+#else
+	vec3 normalW = vec3(1.0, 1.0, 1.0);
+#endif
+
+	// Lighting
+	vec3 diffuseBase = vec3(0., 0., 0.);
+	float shadow = 1.;
+
+#ifdef LIGHT0
+#ifdef SPOTLIGHT0
+	lightingInfo info = computeSpotLighting(viewDirectionW, normalW, vLightData0, vLightDirection0, vLightDiffuse0.rgb, vLightDiffuse0.a);
+#endif
+#ifdef HEMILIGHT0
+	lightingInfo info = computeHemisphericLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightGround0);
+#endif
+#if defined(POINTLIGHT0) || defined(DIRLIGHT0)
+	lightingInfo info = computeLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightDiffuse0.a);
+#endif
+#ifdef SHADOW0
+#ifdef SHADOWVSM0
+	shadow = computeShadowWithVSM(vPositionFromLight0, shadowSampler0, shadowsInfo0.z, shadowsInfo0.x);
+#else
+#ifdef SHADOWPCF0
+	#if defined(POINTLIGHT0)
+	shadow = computeShadowWithPCFCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.z, shadowsInfo0.x);
+	#else
+	shadow = computeShadowWithPCF(vPositionFromLight0, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x);
+	#endif
+#else
+	#if defined(POINTLIGHT0)
+	shadow = computeShadowCube(vLightData0.xyz, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z);
+	#else
+	shadow = computeShadow(vPositionFromLight0, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z);
+	#endif
+#endif
+#endif
+#else
+	shadow = 1.;
+#endif
+	diffuseBase += info.diffuse * shadow;
+#endif
+
+#ifdef LIGHT1
+#ifdef SPOTLIGHT1
+	info = computeSpotLighting(viewDirectionW, normalW, vLightData1, vLightDirection1, vLightDiffuse1.rgb, vLightDiffuse1.a);
+#endif
+#ifdef HEMILIGHT1
+	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightGround1.a);
+#endif
+#if defined(POINTLIGHT1) || defined(DIRLIGHT1)
+	info = computeLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightDiffuse1.a);
+#endif
+#ifdef SHADOW1
+#ifdef SHADOWVSM1
+	shadow = computeShadowWithVSM(vPositionFromLight1, shadowSampler1, shadowsInfo1.z, shadowsInfo1.x);
+#else
+#ifdef SHADOWPCF1
+#if defined(POINTLIGHT1)
+	shadow = computeShadowWithPCFCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.z, shadowsInfo1.x);
+#else
+	shadow = computeShadowWithPCF(vPositionFromLight1, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x);
+#endif
+#else
+	#if defined(POINTLIGHT1)
+	shadow = computeShadowCube(vLightData1.xyz, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z);
+	#else
+	shadow = computeShadow(vPositionFromLight1, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z);
+	#endif
+#endif
+#endif
+#else
+	shadow = 1.;
+#endif
+	diffuseBase += info.diffuse * shadow;
+#endif
+
+#ifdef LIGHT2
+#ifdef SPOTLIGHT2
+	info = computeSpotLighting(viewDirectionW, normalW, vLightData2, vLightDirection2, vLightDiffuse2.rgb, vLightDiffuse2.a);
+#endif
+#ifdef HEMILIGHT2
+	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightGround2);
+#endif
+#if defined(POINTLIGHT2) || defined(DIRLIGHT2)
+	info = computeLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightDiffuse2.a);
+#endif
+#ifdef SHADOW2
+#ifdef SHADOWVSM2
+	shadow = computeShadowWithVSM(vPositionFromLight2, shadowSampler2, shadowsInfo2.z, shadowsInfo2.x);
+#else
+#ifdef SHADOWPCF2
+#if defined(POINTLIGHT2)
+	shadow = computeShadowWithPCFCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.z, shadowsInfo2.x);
+#else
+	shadow = computeShadowWithPCF(vPositionFromLight2, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x);
+#endif
+#else
+	#if defined(POINTLIGHT2)
+	shadow = computeShadowCube(vLightData2.xyz, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z);
+	#else
+	shadow = computeShadow(vPositionFromLight2, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z);
+	#endif
+#endif	
+#endif	
+#else
+	shadow = 1.;
+#endif
+	diffuseBase += info.diffuse * shadow;
+#endif
+
+#ifdef LIGHT3
+#ifdef SPOTLIGHT3
+	info = computeSpotLighting(viewDirectionW, normalW, vLightData3, vLightDirection3, vLightDiffuse3.rgb, vLightDiffuse3.a);
+#endif
+#ifdef HEMILIGHT3
+	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightGround3);
+#endif
+#if defined(POINTLIGHT3) || defined(DIRLIGHT3)
+	info = computeLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightDiffuse3.a);
+#endif
+#ifdef SHADOW3
+#ifdef SHADOWVSM3
+		shadow = computeShadowWithVSM(vPositionFromLight3, shadowSampler3, shadowsInfo3.z, shadowsInfo3.x);
+#else
+#ifdef SHADOWPCF3
+#if defined(POINTLIGHT3)
+	shadow = computeShadowWithPCFCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.z, shadowsInfo3.x);
+#else
+	shadow = computeShadowWithPCF(vPositionFromLight3, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);
+#endif
+#else
+	#if defined(POINTLIGHT3)
+	shadow = computeShadowCube(vLightData3.xyz, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);
+	#else
+	shadow = computeShadow(vPositionFromLight3, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);
+	#endif
+#endif	
+#endif	
+#else
+	shadow = 1.;
+#endif
+	diffuseBase += info.diffuse * shadow;
+#endif
+
+#ifdef VERTEXALPHA
+	alpha *= vColor.a;
+#endif
+
+	vec3 finalDiffuse = clamp(diffuseBase * diffuseColor, 0.0, 1.0) * baseColor.rgb;
+
+	// Composition
+	//float r = Rand(vPositionW) * 0.5;
+	float r = vfur_length * 0.5;
+	vec4 color = vec4(finalDiffuse * (0.5 + r), alpha);
+
+#ifdef FOG
+	float fog = CalcFogFactor();
+	color.rgb = fog * color.rgb + (1.0 - fog) * vFogColor;
+#endif
+
+	gl_FragColor = color;
+}

+ 202 - 0
materialsLibrary/materials/fur/fur.vertex.fx

@@ -0,0 +1,202 @@
+precision highp float;
+
+// Attributes
+attribute vec3 position;
+attribute vec3 normal;
+
+#ifdef UV1
+attribute vec2 uv;
+#endif
+#ifdef UV2
+attribute vec2 uv2;
+#endif
+#ifdef VERTEXCOLOR
+attribute vec4 color;
+#endif
+#ifdef BONES
+attribute vec4 matricesIndices;
+attribute vec4 matricesWeights;
+#endif
+
+
+// Uniforms
+uniform float furLength;
+uniform float furAngle;
+#ifdef HEIGHTMAP
+uniform sampler2D heightTexture;
+#endif
+
+#ifdef INSTANCES
+attribute vec4 world0;
+attribute vec4 world1;
+attribute vec4 world2;
+attribute vec4 world3;
+#else
+uniform mat4 world;
+#endif
+
+uniform mat4 view;
+uniform mat4 viewProjection;
+
+#ifdef DIFFUSE
+varying vec2 vDiffuseUV;
+uniform mat4 diffuseMatrix;
+uniform vec2 vDiffuseInfos;
+#endif
+
+#ifdef BONES
+uniform mat4 mBones[BonesPerMesh];
+#endif
+
+#ifdef POINTSIZE
+uniform float pointSize;
+#endif
+
+// Output
+varying vec3 vPositionW;
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+varying float vfur_length;
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+#ifdef CLIPPLANE
+uniform vec4 vClipPlane;
+varying float fClipDistance;
+#endif
+
+#ifdef FOG
+varying float fFogDistance;
+#endif
+
+#ifdef SHADOWS
+#if defined(SPOTLIGHT0) || defined(DIRLIGHT0)
+uniform mat4 lightMatrix0;
+varying vec4 vPositionFromLight0;
+#endif
+#if defined(SPOTLIGHT1) || defined(DIRLIGHT1)
+uniform mat4 lightMatrix1;
+varying vec4 vPositionFromLight1;
+#endif
+#if defined(SPOTLIGHT2) || defined(DIRLIGHT2)
+uniform mat4 lightMatrix2;
+varying vec4 vPositionFromLight2;
+#endif
+#if defined(SPOTLIGHT3) || defined(DIRLIGHT3)
+uniform mat4 lightMatrix3;
+varying vec4 vPositionFromLight3;
+#endif
+#endif
+
+float Rand(vec3 rv) {
+	float x = dot(rv, vec3(12.9898,78.233, 24.65487));
+	return fract(sin(x) * 43758.5453);
+}
+
+void main(void) {
+	mat4 finalWorld;
+
+#ifdef INSTANCES
+	finalWorld = mat4(world0, world1, world2, world3);
+#else
+	finalWorld = world;
+#endif
+
+#ifdef BONES
+	mat4 m0 = mBones[int(matricesIndices.x)] * matricesWeights.x;
+	mat4 m1 = mBones[int(matricesIndices.y)] * matricesWeights.y;
+	mat4 m2 = mBones[int(matricesIndices.z)] * matricesWeights.z;
+
+#ifdef BONES4
+	mat4 m3 = mBones[int(matricesIndices.w)] * matricesWeights.w;
+	finalWorld = finalWorld * (m0 + m1 + m2 + m3);
+#else
+	finalWorld = finalWorld * (m0 + m1 + m2);
+#endif 
+
+#endif
+//FUR
+float r = Rand(position);
+#ifdef HEIGHTMAP	
+	vfur_length = furLength * texture2D(heightTexture, uv).rgb.x;
+#else	
+	vfur_length = (furLength * r);
+#endif
+	vec3 tangent1 = vec3(normal.y, -normal.x, 0);
+	vec3 tangent2 = vec3(-normal.z, 0, normal.x);
+	r = Rand(tangent1*r);
+	float J = (2.0 + 4.0* r);
+	r = Rand(tangent2*r);
+	float K = (2.0 + 2.0* r);
+	tangent1 = tangent1*J + tangent2*K;
+	tangent1 = normalize(tangent1);
+    vec3 newPosition = position + normal * vfur_length*cos(furAngle) + tangent1*vfur_length*sin(furAngle);
+	
+//END FUR
+	gl_Position = viewProjection * finalWorld * vec4(newPosition, 1.0);
+
+	vec4 worldPos = finalWorld * vec4(newPosition, 1.0);
+	vPositionW = vec3(worldPos);
+
+#ifdef NORMAL
+	vNormalW = normalize(vec3(finalWorld * vec4(normal, 0.0)));
+#endif
+
+	// Texture coordinates
+#ifndef UV1
+	vec2 uv = vec2(0., 0.);
+#endif
+#ifndef UV2
+	vec2 uv2 = vec2(0., 0.);
+#endif
+
+#ifdef DIFFUSE
+	if (vDiffuseInfos.x == 0.)
+	{
+		vDiffuseUV = vec2(diffuseMatrix * vec4(uv, 1.0, 0.0));
+	}
+	else
+	{
+		vDiffuseUV = vec2(diffuseMatrix * vec4(uv2, 1.0, 0.0));
+	}
+#endif
+
+	// Clip plane
+#ifdef CLIPPLANE
+	fClipDistance = dot(worldPos, vClipPlane);
+#endif
+
+	// Fog
+#ifdef FOG
+	fFogDistance = (view * worldPos).z;
+#endif
+
+	// Shadows
+#ifdef SHADOWS
+#if defined(SPOTLIGHT0) || defined(DIRLIGHT0)
+	vPositionFromLight0 = lightMatrix0 * worldPos;
+#endif
+#if defined(SPOTLIGHT1) || defined(DIRLIGHT1)
+	vPositionFromLight1 = lightMatrix1 * worldPos;
+#endif
+#if defined(SPOTLIGHT2) || defined(DIRLIGHT2)
+	vPositionFromLight2 = lightMatrix2 * worldPos;
+#endif
+#if defined(SPOTLIGHT3) || defined(DIRLIGHT3)
+	vPositionFromLight3 = lightMatrix3 * worldPos;
+#endif
+#endif
+
+	// Vertex color
+#ifdef VERTEXCOLOR
+	vColor = color;
+#endif
+
+	// Point size
+#ifdef POINTSIZE
+	gl_PointSize = pointSize;
+#endif
+}

+ 236 - 0
materialsLibrary/materials/fur/readme.md

@@ -0,0 +1,236 @@
+# Fur material
+
+## Using the fur material
+
+The fur material needs a high number of the triangular facets that make up a mesh to work well.
+The number of facets needed also depends on the size of the mesh.
+Example that seem to work for ground and sphere are:
+
+```
+var ground = BABYLON.Mesh.CreateGround("ground", 8, 8, 200, scene);
+var sphere = BABYLON.Mesh.CreateSphere("sphere", 500, 8, scene);
+```
+
+The fur material is created using 
+
+```
+var furMaterial = new BABYLON.furMaterial("fur_material", scene);
+waterMaterial.bumpTexture = new BABYLON.Texture("bump.png", scene); // Set the bump texture
+
+ground.material = waterMaterial;
+```
+
+## Customize the fur material
+
+You can customise three properties of the fur material:
+
+```
+furMaterial.furLength = 3; // Represents the maximum length of the fur, which is then adjusted randomly. Default value is 1.
+furMaterial.furAngle = Math.PI/6; // Represents the angle the fur lies on the mesh from 0 to Math.PI/2. The default angle of 0 gives fur sticking straight up and PI/2 lies along the mesh.
+furMaterial.furColor = new BABYLON.Color3(0.44, 0.21, 0.02); // is the default color if furColor is not set.
+```
+
+## Using textures
+
+#heightTexture
+
+A greyscale image can be used to set the fur length. 
+A speckled greyscale image can produce fur like results.
+Any greyscale image with affect the fur length producing a heightMap type effect.
+
+```
+furMaterial.heightTexture = new BABYLON.Texture("speckles.jpg", scene); // Set the fur length with a texture.
+```
+#diffuseTexture
+A texture can also be used to paint the mesh. 
+The leopard fur texture used in the test is by Martin Wegmann from [Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Leopard_fur.JPG)
+under the [license](https://creativecommons.org/licenses/by-sa/3.0/deed.en)
+
+```
+furMaterial.diffuseTexture = new BABYLON.Texture("leopard_fur.jpg", scene); // Set the fur length with a texture.
+```
+
+## Meshes where the number of facets is not user controlled on creation.
+
+Unlike the ground mesh where you can supply the number of subdivisions or the sphere mesh where you can supply the number of segments the majority of meshes are created using a minimum number of facets.
+To apply the fur material to these the number of facets per face of the mesh needs to be increased.
+
+The function increasedFacets will do this:
+When n is the number of points per side added to each side of a facet the number of facets is increased by the square of (n + 1).
+
+```
+function increasedFacets(mesh, pps) { //pps points per side		
+	var gaps = pps+1;
+	var n = gaps + 1;
+	var fvs =[];
+	for(var i=0; i<n; i++) {
+		fvs[i] = [];
+	}	
+	var A,B;
+	var d ={x:0,y:0,z:0};
+	var u ={x:0,y:0};
+	var indices = [];
+	var vertexIndex = [];
+	var side = [];
+	var uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
+	var meshIndices = mesh.getIndices();
+	var positions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);	
+	var normals =[];	
+	
+	for(var i = 0; i<meshIndices.length; i+=3) {
+		vertexIndex[0] = meshIndices[i];
+		vertexIndex[1] = meshIndices[i + 1];
+		vertexIndex[2] = meshIndices[i + 2];		
+		for(var j = 0; j<3; j++) {
+			A = vertexIndex[j];
+			B = vertexIndex[(j+1)%3];		
+			if(side[A] === undefined  && side[B] ===  undefined) {			
+				side[A] = [];
+				side[B] = [];			
+			}
+			else {
+				if(side[A] === undefined) {					
+					side[A] = [];
+				}
+				if(side[B] === undefined) {					
+					side[B] = [];								
+				}
+			}
+			if(side[A][B]  === undefined  && side[B][A] === undefined) {			
+				side[A][B] = [];
+				d.x = (positions[3 * B] - positions[3 * A])/gaps;
+				d.y = (positions[3 * B + 1] - positions[3 * A + 1])/gaps;
+				d.z = (positions[3 * B + 2] - positions[3 * A + 2])/gaps;
+				u.x = (uvs[2*B] - uvs[2*A])/gaps;
+				u.y = (uvs[2*B + 1] - uvs[2*A + 1])/gaps;
+				side[A][B].push(A);				
+				for(var k=1; k<gaps; k++) {				
+					side[A][B].push(positions.length/3);				
+					positions.push(positions[3 * A] + k*d.x, positions[3 * A + 1] + k*d.y, positions[3 * A + 2] + k*d.z);
+					uvs.push(uvs[2*A] + k*u.x, uvs[2*A + 1] + k*u.y);
+				}				
+				side[A][B].push(B);
+				side[B][A]=[];
+				l = side[A][B].length;
+				for(var a=0; a<l; a++) {
+					side[B][A][a] = side[A][B][l-1-a];
+				}
+			}
+			else {
+				if(side[A][B] === undefined) {			
+					side[A][B]=[];
+					l = side[B][A].length;
+					for(var a=0; a<l; a++) {
+						side[A][B][a] = side[B][A][l-1-a];
+					}
+				}
+				if(side[B][A] === undefined) {			
+					side[B][A]=[];				
+					l = side[A][B].length;
+					for(var a=0; a<l; a++) {
+						side[B][A][a] = side[A][B][l-1-a];
+					}
+				}
+			}					
+		}	
+		fvs[0][0] = meshIndices[i];
+		fvs[1][0] = side[meshIndices[i]][meshIndices[i + 1]][1];
+		fvs[1][1] = side[meshIndices[i]][meshIndices[i + 2]][1];		
+		for(var k = 2; k<gaps; k++) {
+			fvs[k][0] = side[meshIndices[i]][meshIndices[i + 1]][k];
+			fvs[k][k] = side[meshIndices[i]][meshIndices[i + 2]][k];		
+			d.x = (positions[3 * fvs[k][k]] - positions[3 * fvs[k][0]])/k;
+			d.y = (positions[3 * fvs[k][k] + 1] - positions[3 * fvs[k][0] + 1])/k;
+			d.z = (positions[3 * fvs[k][k] + 2] - positions[3 * fvs[k][0] + 2])/k;
+			u.x = (uvs[2*fvs[k][k]] - uvs[2*fvs[k][0]])/k;
+			u.y = (uvs[2*fvs[k][k] + 1] - uvs[2*fvs[k][0] + 1])/k;
+			for(var j = 1; j<k; j++) {				
+				fvs[k][j] = positions.length/3;				
+				positions.push(positions[3 * fvs[k][0]] + j*d.x, positions[3 * fvs[k][0] + 1] + j*d.y, positions[3 * fvs[k][0] + 2] + j*d.z);
+				uvs.push(uvs[2*fvs[k][0]] + j*u.x, uvs[2*fvs[k][0] + 1] + j*u.y);
+			}		
+		}
+		fvs[gaps] = side[meshIndices[i + 1]][meshIndices[i + 2]];
+		
+		indices.push(fvs[0][0],fvs[1][0],fvs[1][1]);
+		for(var k = 1; k<gaps; k++) {
+			for(var j = 0; j<k; j++) {			
+				indices.push(fvs[k][j],fvs[k+1][j],fvs[k+1][j+1]);
+				indices.push(fvs[k][j],fvs[k+1][j+1],fvs[k][j+1]);
+			}		
+			indices.push(fvs[k][j],fvs[k+1][j],fvs[k+1][j+1]);
+		}
+
+	}							
+
+	var vertexData = new BABYLON.VertexData();
+	vertexData.positions = positions;
+	vertexData.indices = indices;
+	vertexData.uvs = uvs;
+	
+	BABYLON.VertexData.ComputeNormals(positions, indices, normals);
+	vertexData.normals = normals;
+	mesh.dispose();
+	var newmesh = new BABYLON.Mesh("newmesh", scene);	
+	vertexData.applyToMesh(newmesh);
+
+	return newmesh;
+}
+```
+
+For sharp edged meshes such as a box the shader can separate the faces since the faces meeting at the corners have there own vertices and normals at these vertices. 
+These meshes are flat shaded. If this separation of the edges is a problem then the function convertToSmoothShadedMesh() can be used.
+However this can then produce some artefacts at the edges.
+
+```
+function convertToSmoothShadedMesh(mesh) {
+	var meshIndices = mesh.getIndices();
+	var meshPositions = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
+	var mesh_uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
+	var setPositions = [];
+	var indices = [];
+	var positions = [];
+	var uvs = [];
+	var normals = [];
+	var p;
+	var indexMap = [];
+	for(var i=0; i<meshPositions.length; i+=3) {
+		var temp =[];
+		temp.push(i/3, meshPositions[i], meshPositions[i + 1], meshPositions[i + 2], mesh_uvs[2*i/3], mesh_uvs[2*i/3 + 1]);
+		setPositions.push(temp);
+	}	
+	var i=0;
+	while(setPositions.length>0) {
+		p = setPositions.shift();
+		positions.push(p[1],p[2],p[3]);
+		uvs.push(p[4],p[5]);
+		indexMap[p[0]] = i;		
+		var j = 0;
+		while(j<setPositions.length) {		
+			if (Math.abs(p[1] - setPositions[j][1])<Math.pow(0.1, 10) && Math.abs(p[2] - setPositions[j][2])<Math.pow(0.1, 10) && Math.abs(p[3] - setPositions[j][3])<Math.pow(0.1, 10) ) {
+				indexMap[setPositions[j][0]] = i;			
+				setPositions.splice(j,1);
+			}
+			else {
+				j++;
+			}
+		}
+		i++;
+	}	
+	for(var i=0; i<meshIndices.length; i++) {
+		indices.push(indexMap[meshIndices[i]]);
+	}
+	
+	var vertexData = new BABYLON.VertexData();
+	vertexData.positions = positions;
+	vertexData.indices = indices;
+	vertexData.uvs = uvs;
+	
+	BABYLON.VertexData.ComputeNormals(positions, indices, normals);
+	vertexData.normals = normals;
+	vertexData.applyToMesh(mesh);
+
+	return mesh;
+	
+}
+```

+ 80 - 15
materialsLibrary/materials/lava/babylon.lavaMaterial.ts

@@ -28,7 +28,7 @@ module BABYLON {
         public POINTLIGHT0 = false;
         public POINTLIGHT1 = false;
         public POINTLIGHT2 = false;
-        public POINTLIGHT3 = false;        
+        public POINTLIGHT3 = false;
         public SHADOW0 = false;
         public SHADOW1 = false;
         public SHADOW2 = false;
@@ -47,8 +47,7 @@ module BABYLON {
         public UV2 = false;
         public VERTEXCOLOR = false;
         public VERTEXALPHA = false;
-        public BONES = false;
-        public BONES4 = false;
+        public NUM_BONE_INFLUENCERS = 0;
         public BonesPerMesh = 0;
         public INSTANCES = false;
 
@@ -63,6 +62,9 @@ module BABYLON {
         public noiseTexture: BaseTexture;
         public fogColor: Color3;
         public speed : number = 1;
+        public movingSpeed : number = 1;
+        public lowFrequencySpeed : number = 1;
+        public fogDensity : number = 0.15;
 
         private _lastTime : number = 0;
 
@@ -143,7 +145,7 @@ module BABYLON {
                         needUVs = true;
                         this._defines.DIFFUSE = true;
                     }
-                }                
+                }
             }
 
             // Effect
@@ -263,10 +265,10 @@ module BABYLON {
                         this._defines.VERTEXALPHA = true;
                     }
                 }
+
                 if (mesh.useBones && mesh.computeBonesUsingShaders) {
-                    this._defines.BONES = true;
+                    this._defines.NUM_BONE_INFLUENCERS = mesh.numBoneInfluencers;
                     this._defines.BonesPerMesh = (mesh.skeleton.bones.length + 1);
-                    this._defines.BONES4 = true;
                 }
 
                 // Instances
@@ -282,7 +284,7 @@ module BABYLON {
                 scene.resetCachedMaterial();
 
                 // Fallbacks
-                var fallbacks = new EffectFallbacks();             
+                var fallbacks = new EffectFallbacks();
                 if (this._defines.FOG) {
                     fallbacks.addFallback(1, "FOG");
                 }
@@ -308,9 +310,9 @@ module BABYLON {
                         fallbacks.addFallback(0, "SHADOWVSM" + lightIndex);
                     }
                 }
-             
-                if (this._defines.BONES4) {
-                    fallbacks.addFallback(0, "BONES4");
+
+                if (this._defines.NUM_BONE_INFLUENCERS > 0){
+                    fallbacks.addCPUSkinningFallback(0, mesh);
                 }
 
                 //Attributes
@@ -332,9 +334,13 @@ module BABYLON {
                     attribs.push(VertexBuffer.ColorKind);
                 }
 
-                if (this._defines.BONES) {
+                if (this._defines.NUM_BONE_INFLUENCERS > 0) {
                     attribs.push(VertexBuffer.MatricesIndicesKind);
                     attribs.push(VertexBuffer.MatricesWeightsKind);
+                    if (this._defines.NUM_BONE_INFLUENCERS > 4) {
+                        attribs.push(VertexBuffer.MatricesIndicesExtraKind);
+                        attribs.push(VertexBuffer.MatricesWeightsExtraKind);
+                    }
                 }
 
                 if (this._defines.INSTANCES) {
@@ -355,10 +361,11 @@ module BABYLON {
                         "vLightData2", "vLightDiffuse2", "vLightSpecular2", "vLightDirection2", "vLightGround2", "lightMatrix2",
                         "vLightData3", "vLightDiffuse3", "vLightSpecular3", "vLightDirection3", "vLightGround3", "lightMatrix3",
                         "vFogInfos", "vFogColor", "pointSize",
-                        "vDiffuseInfos", 
+                        "vDiffuseInfos",
                         "mBones",
                         "vClipPlane", "diffuseMatrix",
-                        "shadowsInfo0", "shadowsInfo1", "shadowsInfo2", "shadowsInfo3","time", "speed", "fogColor"
+                        "shadowsInfo0", "shadowsInfo1", "shadowsInfo2", "shadowsInfo3","time", "speed","movingSpeed",
+                        "fogColor","fogDensity", "lowFrequencySpeed"
                     ],
                     ["diffuseSampler",
                         "shadowSampler0", "shadowSampler1", "shadowSampler2", "shadowSampler3", "noiseTexture"
@@ -423,7 +430,7 @@ module BABYLON {
                     this._effect.setFloat("pointSize", this.pointSize);
                 }
 
-                this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);                
+                this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);
             }
 
             this._effect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility);
@@ -494,6 +501,10 @@ module BABYLON {
                 this.fogColor = Color3.Black();
             }
             this._effect.setColor3("fogColor", this.fogColor);
+            this._effect.setFloat("fogDensity", this.fogDensity);
+
+            this._effect.setFloat("lowFrequencySpeed", this.lowFrequencySpeed);
+            this._effect.setFloat("movingSpeed", this.movingSpeed);
 
 
             super.bind(world, mesh);
@@ -543,6 +554,60 @@ module BABYLON {
 
             return newMaterial;
         }
+
+
+        public serialize(): any {
+            var serializationObject = super.serialize();
+            serializationObject.customType      = "BABYLON.LavaMaterial";
+            serializationObject.diffuseColor    = this.diffuseColor.asArray();
+            serializationObject.fogColor        = this.fogColor.asArray();
+            serializationObject.speed           = this.speed;
+            serializationObject.movingSpeed     = this.movingSpeed;
+            serializationObject.lowFrequencySpeed = this.lowFrequencySpeed;
+            serializationObject.fogDensity      = this.fogDensity;
+            serializationObject.checkReadyOnlyOnce = this.checkReadyOnlyOnce;
+
+            if (this.diffuseTexture) {
+                serializationObject.diffuseTexture = this.diffuseTexture.serialize();
+            }
+            if (this.noiseTexture) {
+                serializationObject.noiseTexture = this.noiseTexture.serialize();
+            }
+
+            return serializationObject;
+        }
+
+        public static Parse(source: any, scene: Scene, rootUrl: string): LavaMaterial {
+            var material = new LavaMaterial(source.name, scene);
+
+            material.diffuseColor   = Color3.FromArray(source.diffuseColor);
+            material.speed          = source.speed;
+            material.fogColor       = Color3.FromArray(source.fogColor);
+            material.movingSpeed    = source.movingSpeed;
+            material.lowFrequencySpeed = source.lowFrequencySpeed;
+            material.fogDensity     =  source.lowFrequencySpeed;
+
+            material.alpha          = source.alpha;
+
+            material.id             = source.id;
+
+            Tags.AddTagsTo(material, source.tags);
+            material.backFaceCulling = source.backFaceCulling;
+            material.wireframe = source.wireframe;
+
+            if (source.diffuseTexture) {
+                material.diffuseTexture = Texture.Parse(source.diffuseTexture, scene, rootUrl);
+            }
+
+            if (source.noiseTexture) {
+                material.noiseTexture = Texture.Parse(source.noiseTexture, scene, rootUrl);
+            }
+
+            if (source.checkReadyOnlyOnce) {
+                material.checkReadyOnlyOnce = source.checkReadyOnlyOnce;
+            }
+
+            return material;
+        }
     }
 } 
-

+ 5 - 4
materialsLibrary/materials/lava/lava.fragment.fx

@@ -10,8 +10,10 @@ varying vec3 vPositionW;
 // MAGMAAAA
 uniform float time;
 uniform float speed;
+uniform float movingSpeed;
 uniform vec3 fogColor;
 uniform sampler2D noiseTexture;
+uniform float fogDensity;
 
 // Varying
 varying float noise;
@@ -402,17 +404,16 @@ void main(void) {
 
 	T1.x += noiseTex.x * 2.0;
 	T1.y += noiseTex.y * 2.0;
-	T2.x -= noiseTex.y * 0.2;
-	T2.y += noiseTex.z * 0.2;
+	T2.x -= noiseTex.y * 0.2 + time*0.001*movingSpeed;
+	T2.y += noiseTex.z * 0.2 + time*0.002*movingSpeed;
 
 	float p = texture2D( noiseTexture, T1 * 3.0 ).a;
 
 	vec4 lavaColor = texture2D( diffuseSampler, T2 * 4.0);
-	vec4 temp = lavaColor * ( vec4( p, p, p, p ) * 2.0 ) + ( lavaColor * lavaColor - 0.1 );
+	vec4 temp = lavaColor * ( vec4( p, p, p, p ) * 2. ) + ( lavaColor * lavaColor - 0.1 );
 
 	baseColor = temp;
 
-	float fogDensity = 0.15;
 	float depth = gl_FragCoord.z * 4.0;
 	const float LOG2 = 1.442695;
     float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );

+ 38 - 19
materialsLibrary/materials/lava/lava.vertex.fx

@@ -1,7 +1,7 @@
 precision highp float;
 // Inputs
 uniform float time;
-uniform float speed;
+uniform float lowFrequencySpeed;
 // Varying
 varying float noise;
 
@@ -19,10 +19,6 @@ attribute vec2 uv2;
 #ifdef VERTEXCOLOR
 attribute vec4 color;
 #endif
-#ifdef BONES
-attribute vec4 matricesIndices;
-attribute vec4 matricesWeights;
-#endif
 
 // Uniforms
 
@@ -44,8 +40,15 @@ uniform mat4 diffuseMatrix;
 uniform vec2 vDiffuseInfos;
 #endif
 
-#ifdef BONES
-uniform mat4 mBones[BonesPerMesh];
+#if NUM_BONE_INFLUENCERS > 0
+	uniform mat4 mBones[BonesPerMesh];
+
+	attribute vec4 matricesIndices;
+	attribute vec4 matricesWeights;
+	#if NUM_BONE_INFLUENCERS > 4
+		attribute vec4 matricesIndicesExtra;
+		attribute vec4 matricesWeightsExtra;
+	#endif
 #endif
 
 #ifdef POINTSIZE
@@ -207,25 +210,41 @@ void main(void) {
 	finalWorld = world;
 #endif
 
-#ifdef BONES
-	mat4 m0 = mBones[int(matricesIndices.x)] * matricesWeights.x;
-	mat4 m1 = mBones[int(matricesIndices.y)] * matricesWeights.y;
-	mat4 m2 = mBones[int(matricesIndices.z)] * matricesWeights.z;
+#if NUM_BONE_INFLUENCERS > 0
+	mat4 influence;
+	influence = mBones[int(matricesIndices[0])] * matricesWeights[0];
 
-#ifdef BONES4
-	mat4 m3 = mBones[int(matricesIndices.w)] * matricesWeights.w;
-	finalWorld = finalWorld * (m0 + m1 + m2 + m3);
-#else
-	finalWorld = finalWorld * (m0 + m1 + m2);
-#endif 
+	#if NUM_BONE_INFLUENCERS > 1
+		influence += mBones[int(matricesIndices[1])] * matricesWeights[1];
+	#endif 
+	#if NUM_BONE_INFLUENCERS > 2
+		influence += mBones[int(matricesIndices[2])] * matricesWeights[2];
+	#endif	
+	#if NUM_BONE_INFLUENCERS > 3
+		influence += mBones[int(matricesIndices[3])] * matricesWeights[3];
+	#endif	
 
+	#if NUM_BONE_INFLUENCERS > 4
+		influence += mBones[int(matricesIndicesExtra[0])] * matricesWeightsExtra[0];
+	#endif
+	#if NUM_BONE_INFLUENCERS > 5
+		influence += mBones[int(matricesIndicesExtra[1])] * matricesWeightsExtra[1];
+	#endif	
+	#if NUM_BONE_INFLUENCERS > 6
+		influence += mBones[int(matricesIndicesExtra[2])] * matricesWeightsExtra[2];
+	#endif	
+	#if NUM_BONE_INFLUENCERS > 7
+		influence += mBones[int(matricesIndicesExtra[3])] * matricesWeightsExtra[3];
+	#endif	
+
+	finalWorld = finalWorld * influence;
 #endif
 
 
     // get a turbulent 3d noise using the normal, normal to high freq
     noise = 10.0 *  -.10 * turbulence( .5 * normal + time*1.15 );
     // get a 3d noise using the position, low frequency
-    float b = 5.0 * pnoise( 0.05 * position +vec3(time*1.025), vec3( 100.0 ) );
+    float b = lowFrequencySpeed * 5.0 * pnoise( 0.05 * position +vec3(time*1.025), vec3( 100.0 ) );
     // compose both noises
     float displacement = - 1.5 * noise + b;
 
@@ -295,4 +314,4 @@ void main(void) {
 #ifdef POINTSIZE
 	gl_PointSize = pointSize;
 #endif
-}
+}

Plik diff jest za duży
+ 555 - 516
materialsLibrary/materials/normal/babylon.normalMaterial.ts


+ 163 - 0
materialsLibrary/materials/pbr/babylon.pbrMaterial.ts

@@ -1119,5 +1119,168 @@ module BABYLON {
 
             return newPBRMaterial;
         }
+        
+        public serialize(): any {
+            var serializationObject = super.serialize();
+                        
+            serializationObject.customType = "BABYLON.PBRMaterial";
+
+            serializationObject.directIntensity = this.directIntensity;
+            serializationObject.emissiveIntensity = this.emissiveIntensity;
+            serializationObject.environmentIntensity = this.environmentIntensity;
+        
+            serializationObject.cameraExposure = this.cameraExposure;
+            serializationObject.cameraContrast = this.cameraContrast;
+
+            serializationObject.overloadedShadowIntensity = this.overloadedShadowIntensity;
+            serializationObject.overloadedShadeIntensity = this.overloadedShadeIntensity;
+        
+            serializationObject.overloadedAmbientIntensity = this.overloadedAmbientIntensity;
+            serializationObject.overloadedDiffuseIntensity = this.overloadedDiffuseIntensity;
+            serializationObject.overloadedSpecularIntensity = this.overloadedSpecularIntensity;
+            serializationObject.overloadedEmissiveIntensity = this.overloadedEmissiveIntensity;
+            serializationObject.overloadedAmbient = this.overloadedAmbient.asArray();
+            serializationObject.overloadedDiffuse = this.overloadedDiffuse.asArray();
+            serializationObject.overloadedSpecular = this.overloadedSpecular.asArray();
+            serializationObject.overloadedEmissive = this.overloadedEmissive.asArray();
+            serializationObject.overloadedReflection = this.overloadedReflection.asArray();
+
+            serializationObject.overloadedGlossiness = this.overloadedGlossiness;
+            serializationObject.overloadedGlossinessIntensity = this.overloadedGlossinessIntensity;
+            serializationObject.overloadedReflectionIntensity = this.overloadedReflectionIntensity;
+        
+            serializationObject.disableBumpMap = this.disableBumpMap;
+
+            // Standard material
+            if (this.diffuseTexture) {
+                serializationObject.diffuseTexture = this.diffuseTexture.serialize();
+            }
+            if (this.ambientTexture) {
+                serializationObject.ambientTexture = this.ambientTexture.serialize();
+            }
+            if (this.opacityTexture) {
+                serializationObject.opacityTexture = this.opacityTexture.serialize();
+            }
+            if (this.reflectionTexture) {
+                serializationObject.reflectionTexture = this.reflectionTexture.serialize();
+            }
+            if (this.emissiveTexture) {
+                serializationObject.emissiveTexture = this.emissiveTexture.serialize();
+            }
+            if (this.specularTexture) {
+                serializationObject.specularTexture = this.specularTexture.serialize();
+            }
+            if (this.bumpTexture) {
+                serializationObject.bumpTexture = this.bumpTexture.serialize();
+            }
+            if (this.lightmapTexture) {
+                serializationObject.lightmapTexture = this.lightmapTexture.serialize();
+                serializationObject.useLightmapAsShadowmap = this.useLightmapAsShadowmap;
+            }
+
+            serializationObject.ambientColor = this.ambientColor.asArray();
+            serializationObject.diffuseColor = this.diffuseColor.asArray();
+            serializationObject.specularColor = this.specularColor.asArray();
+            serializationObject.reflectionColor = this.reflectionColor.asArray();
+            serializationObject.glossiness = this.glossiness;
+            serializationObject.emissiveColor = this.emissiveColor.asArray();
+            serializationObject.useAlphaFromDiffuseTexture = this.useAlphaFromDiffuseTexture;
+            serializationObject.useEmissiveAsIllumination = this.useEmissiveAsIllumination;
+            serializationObject.useGlossinessFromSpecularMapAlpha = this.useGlossinessFromSpecularMapAlpha;
+            serializationObject.useSpecularOverAlpha = this.useSpecularOverAlpha;
+            
+            serializationObject.emissiveFresnelParameters = this.emissiveFresnelParameters.serialize();
+            serializationObject.opacityFresnelParameters = this.opacityFresnelParameters.serialize();
+
+            return serializationObject;
+        }
+                
+        public static Parse(source: any, scene: Scene, rootUrl: string): PBRMaterial {
+            var material = new PBRMaterial(source.name, scene);
+            
+            material.alpha = source.alpha;
+            material.id = source.id;
+            
+            if (source.disableDepthWrite) {
+                material.disableDepthWrite = source.disableDepthWrite;
+            }
+            
+           if (source.checkReadyOnlyOnce) {
+                material.checkReadyOnlyOnce = source.checkReadyOnlyOnce;
+            }
+
+            Tags.AddTagsTo(material, source.tags);
+            material.backFaceCulling = source.backFaceCulling;
+            material.wireframe = source.wireframe;
+            
+            material.directIntensity = source.directIntensity;
+            material.emissiveIntensity = source.emissiveIntensity;
+            material.environmentIntensity = source.environmentIntensity;
+        
+            material.cameraExposure = source.cameraExposure;
+            material.cameraContrast = source.cameraContrast;
+
+            material.overloadedShadowIntensity = source.overloadedShadowIntensity;
+            material.overloadedShadeIntensity = source.overloadedShadeIntensity;
+        
+            material.overloadedAmbientIntensity = source.overloadedAmbientIntensity;
+            material.overloadedDiffuseIntensity = source.overloadedDiffuseIntensity;
+            material.overloadedSpecularIntensity = source.overloadedSpecularIntensity;
+            material.overloadedEmissiveIntensity = source.overloadedEmissiveIntensity;
+            material.overloadedAmbient = Color3.FromArray(source.overloadedAmbient);
+            material.overloadedDiffuse = Color3.FromArray(source.overloadedDiffuse);
+            material.overloadedSpecular = Color3.FromArray(source.overloadedSpecular);
+            material.overloadedEmissive = Color3.FromArray(source.overloadedEmissive);
+            material.overloadedReflection = Color3.FromArray(source.overloadedReflection);
+
+            material.overloadedGlossiness = source.overloadedGlossiness;
+            material.overloadedGlossinessIntensity = source.overloadedGlossinessIntensity;
+            material.overloadedReflectionIntensity = source.overloadedReflectionIntensity;
+        
+            material.disableBumpMap = source.disableBumpMap;
+
+            // Standard material
+            if (source.diffuseTexture) {
+                material.diffuseTexture = Texture.Parse(source.diffuseTexture, scene, rootUrl);
+            }
+            if (source.ambientTexture) {
+                material.ambientTexture = Texture.Parse(source.ambientTexture, scene, rootUrl);
+            }
+            if (source.opacityTexture) {
+                material.opacityTexture = Texture.Parse(source.opacityTexture, scene, rootUrl);
+            }
+            if (source.reflectionTexture) {
+                material.reflectionTexture = Texture.Parse(source.reflectionTexture, scene, rootUrl);
+            }
+            if (source.emissiveTexture) {
+                material.emissiveTexture = Texture.Parse(source.emissiveTexture, scene, rootUrl);
+            }
+            if (source.specularTexture) {
+                material.specularTexture = Texture.Parse(source.specularTexture, scene, rootUrl);
+            }
+            if (source.bumpTexture) {
+                material.bumpTexture = Texture.Parse(source.bumpTexture, scene, rootUrl);
+            }
+            if (source.lightmapTexture) {
+                material.lightmapTexture = Texture.Parse(source.lightmapTexture, scene, rootUrl);
+                material.useLightmapAsShadowmap = source.useLightmapAsShadowmap;
+            }
+
+            material.ambientColor = Color3.FromArray(source.ambient);
+            material.diffuseColor = Color3.FromArray(source.diffuse);
+            material.specularColor = Color3.FromArray(source.specular);
+            material.reflectionColor = Color3.FromArray(source.reflectionColor);
+            material.glossiness = source.glossiness;
+            material.emissiveColor = Color3.FromArray(source.emissive);
+            material.useAlphaFromDiffuseTexture = source.useAlphaFromDiffuseTexture;
+            material.useEmissiveAsIllumination = source.useEmissiveAsIllumination;
+            material.useGlossinessFromSpecularMapAlpha = source.useGlossinessFromSpecularMapAlpha;
+            material.useSpecularOverAlpha = source.useSpecularOverAlpha;
+            
+            material.emissiveFresnelParameters = FresnelParameters.Parse(source.emissiveFresnelParameters);
+            material.opacityFresnelParameters = FresnelParameters.Parse(source.opacityFresnelParameters);
+       
+            return material;
+        }
     }
 }

Plik diff jest za duży
+ 554 - 516
materialsLibrary/materials/simple/babylon.simpleMaterial.ts


Plik diff jest za duży
+ 664 - 577
materialsLibrary/materials/terrain/babylon.terrainMaterial.ts


+ 64 - 1
materialsLibrary/materials/water/babylon.waterMaterial.ts

@@ -128,7 +128,7 @@ module BABYLON {
 		/**
 		* Constructor
 		*/
-		constructor(name: string, scene: Scene, renderTargetSize: Vector2 = new Vector2(512, 512)) {
+		constructor(name: string, scene: Scene, public renderTargetSize: Vector2 = new Vector2(512, 512)) {
             super(name, scene);
 			
 			// Create render targets
@@ -720,6 +720,69 @@ module BABYLON {
             return newMaterial;
         }
         
+		public serialize(): any {
+		        		
+            var serializationObject = super.serialize();
+			
+             serializationObject.customType         = "BABYLON.WaterMaterial";
+            serializationObject.diffuseColor    	= this.diffuseColor.asArray();
+			serializationObject.specularColor   	= this.specularColor.asArray();
+            serializationObject.specularPower   	= this.specularPower;
+            serializationObject.disableLighting 	= this.disableLighting;
+            serializationObject.windForce     		= this.windForce;
+            serializationObject.windDirection 		= this.windDirection.asArray();
+            serializationObject.waveHeight      	= this.waveHeight;
+            serializationObject.bumpHeight 			= this.bumpHeight;
+			serializationObject.waterColor 			= this.waterColor.asArray();
+			serializationObject.colorBlendFactor	= this.colorBlendFactor;
+			serializationObject.waveLength 			= this.waveLength;
+			serializationObject.renderTargetSize	= this.renderTargetSize.asArray();
+			
+            if (this.bumpTexture) {
+                serializationObject.bumpTexture 	= this.bumpTexture.serialize();
+            }
+
+            return serializationObject;
+        }
+
+        public static Parse(source: any, scene: Scene, rootUrl: string): WaterMaterial {
+		
+			var renderTargetSize = source.renderTargetSize ? Vector2.FromArray(source.renderTargetSize) : null;
+		
+            var material = new WaterMaterial(source.name, scene, renderTargetSize);
+
+            material.diffuseColor    	= Color3.FromArray(source.diffuseColor);
+			material.specularColor   	= Color3.FromArray(source.specularColor);
+            material.specularPower   	= source.specularPower;
+            material.disableLighting 	= source.disableLighting;
+            material.windForce     		= source.windForce;
+            material.windDirection 		= Vector2.FromArray(source.windDirection);
+            material.waveHeight      	= source.waveHeight;
+            material.bumpHeight 		= source.bumpHeight;
+			material.waterColor 		= Color3.FromArray(source.waterColor);
+			material.colorBlendFactor	= source.colorBlendFactor;
+			material.waveLength 		= source.waveLength;
+			material.renderTargetSize	= Vector2.FromArray(source.renderTargetSize);
+
+            material.alpha          = source.alpha;
+
+            material.id             = source.id;
+
+            Tags.AddTagsTo(material, source.tags);
+            material.backFaceCulling = source.backFaceCulling;
+            material.wireframe = source.wireframe;
+
+            if (source.bumpTexture) {
+                material.bumpTexture = Texture.Parse(source.bumpTexture, scene, rootUrl);
+            }
+
+            if (source.checkReadyOnlyOnce) {
+                material.checkReadyOnlyOnce = source.checkReadyOnlyOnce;
+            }
+
+            return material;
+        }
+		
 		public static CreateDefaultMesh(name: string, scene: Scene): Mesh {
 			var mesh = Mesh.CreateGround(name, 512, 512, 32, scene, false);
 			return mesh;

+ 209 - 209
materialsLibrary/materials/water/water.vertex.fx

@@ -1,209 +1,209 @@
-precision highp float;
-
-// Attributes
-attribute vec3 position;
-#ifdef NORMAL
-attribute vec3 normal;
-#endif
-#ifdef UV1
-attribute vec2 uv;
-#endif
-#ifdef UV2
-attribute vec2 uv2;
-#endif
-#ifdef VERTEXCOLOR
-attribute vec4 color;
-#endif
-#ifdef BONES
-attribute vec4 matricesIndices;
-attribute vec4 matricesWeights;
-#endif
-
-// Uniforms
-
-#ifdef INSTANCES
-attribute vec4 world0;
-attribute vec4 world1;
-attribute vec4 world2;
-attribute vec4 world3;
-#else
-uniform mat4 world;
-#endif
-
-uniform mat4 view;
-uniform mat4 viewProjection;
-
-#ifdef BUMP
-varying vec2 vNormalUV;
-uniform mat4 normalMatrix;
-uniform vec2 vNormalInfos;
-#endif
-
-#ifdef BONES
-uniform mat4 mBones[BonesPerMesh];
-#endif
-
-#ifdef POINTSIZE
-uniform float pointSize;
-#endif
-
-// Output
-varying vec3 vPositionW;
-#ifdef NORMAL
-varying vec3 vNormalW;
-#endif
-
-#ifdef VERTEXCOLOR
-varying vec4 vColor;
-#endif
-
-#ifdef CLIPPLANE
-uniform vec4 vClipPlane;
-varying float fClipDistance;
-#endif
-
-#ifdef FOG
-varying float fFogDistance;
-#endif
-
-#ifdef SHADOWS
-#if defined(SPOTLIGHT0) || defined(DIRLIGHT0)
-uniform mat4 lightMatrix0;
-varying vec4 vPositionFromLight0;
-#endif
-#if defined(SPOTLIGHT1) || defined(DIRLIGHT1)
-uniform mat4 lightMatrix1;
-varying vec4 vPositionFromLight1;
-#endif
-#if defined(SPOTLIGHT2) || defined(DIRLIGHT2)
-uniform mat4 lightMatrix2;
-varying vec4 vPositionFromLight2;
-#endif
-#if defined(SPOTLIGHT3) || defined(DIRLIGHT3)
-uniform mat4 lightMatrix3;
-varying vec4 vPositionFromLight3;
-#endif
-#endif
-
-// Water uniforms
-uniform mat4 worldReflectionViewProjection;
-uniform vec2 windDirection;
-uniform float waveLength;
-uniform float time;
-uniform float windForce;
-uniform float waveHeight;
-uniform float waveSpeed;
-
-// Water varyings
-varying vec3 vPosition;
-varying vec3 vRefractionMapTexCoord;
-varying vec3 vReflectionMapTexCoord;
-
-void main(void) {
-	mat4 finalWorld;
-
-#ifdef INSTANCES
-	finalWorld = mat4(world0, world1, world2, world3);
-#else
-	finalWorld = world;
-#endif
-
-#ifdef BONES
-	mat4 m0 = mBones[int(matricesIndices.x)] * matricesWeights.x;
-	mat4 m1 = mBones[int(matricesIndices.y)] * matricesWeights.y;
-	mat4 m2 = mBones[int(matricesIndices.z)] * matricesWeights.z;
-
-#ifdef BONES4
-	mat4 m3 = mBones[int(matricesIndices.w)] * matricesWeights.w;
-	finalWorld = finalWorld * (m0 + m1 + m2 + m3);
-#else
-	finalWorld = finalWorld * (m0 + m1 + m2);
-#endif 
-
-#endif
-
-	vec4 worldPos = finalWorld * vec4(position, 1.0);
-	vPositionW = vec3(worldPos);
-
-#ifdef NORMAL
-	vNormalW = normalize(vec3(finalWorld * vec4(normal, 0.0)));
-#endif
-
-	// Texture coordinates
-#ifndef UV1
-	vec2 uv = vec2(0., 0.);
-#endif
-#ifndef UV2
-	vec2 uv2 = vec2(0., 0.);
-#endif
-
-#ifdef BUMP
-	if (vNormalInfos.x == 0.)
-	{
-		vNormalUV = vec2(normalMatrix * vec4((uv * 1.0) / waveLength + time * windForce * windDirection, 1.0, 0.0));
-	}
-	else
-	{
-		vNormalUV = vec2(normalMatrix * vec4((uv2 * 1.0) / waveLength + time * windForce * windDirection, 1.0, 0.0));
-	}
-#endif
-
-	// Clip plane
-#ifdef CLIPPLANE
-	fClipDistance = dot(worldPos, vClipPlane);
-#endif
-
-	// Fog
-#ifdef FOG
-	fFogDistance = (view * worldPos).z;
-#endif
-
-	// Shadows
-#ifdef SHADOWS
-#if defined(SPOTLIGHT0) || defined(DIRLIGHT0)
-	vPositionFromLight0 = lightMatrix0 * worldPos;
-#endif
-#if defined(SPOTLIGHT1) || defined(DIRLIGHT1)
-	vPositionFromLight1 = lightMatrix1 * worldPos;
-#endif
-#if defined(SPOTLIGHT2) || defined(DIRLIGHT2)
-	vPositionFromLight2 = lightMatrix2 * worldPos;
-#endif
-#if defined(SPOTLIGHT3) || defined(DIRLIGHT3)
-	vPositionFromLight3 = lightMatrix3 * worldPos;
-#endif
-#endif
-
-	// Vertex color
-#ifdef VERTEXCOLOR
-	vColor = color;
-#endif
-
-	// Point size
-#ifdef POINTSIZE
-	gl_PointSize = pointSize;
-#endif
-
-	vec3 p = position;
-	float newY = (sin(((p.x / 0.05) + time * waveSpeed * windForce) * windDirection.x) * waveHeight * 5.0)
-			   + (cos(((p.z / 0.05) + time * waveSpeed * windForce) * windDirection.y) * waveHeight * 5.0);
-	p.y += abs(newY);
-	
-	gl_Position = viewProjection * finalWorld * vec4(p, 1.0);
-
-#ifdef REFLECTION
-	worldPos = viewProjection * finalWorld * vec4(p, 1.0);
-	
-	// Water
-	vPosition = position;
-	
-	vRefractionMapTexCoord.x = 0.5 * (worldPos.w + worldPos.x);
-	vRefractionMapTexCoord.y = 0.5 * (worldPos.w + worldPos.y);
-	vRefractionMapTexCoord.z = worldPos.w;
-	
-	worldPos = worldReflectionViewProjection * vec4(position, 1.0);
-	vReflectionMapTexCoord.x = 0.5 * (worldPos.w + worldPos.x);
-	vReflectionMapTexCoord.y = 0.5 * (worldPos.w + worldPos.y);
-	vReflectionMapTexCoord.z = worldPos.w;
-#endif
-}
+precision highp float;
+
+// Attributes
+attribute vec3 position;
+#ifdef NORMAL
+attribute vec3 normal;
+#endif
+#ifdef UV1
+attribute vec2 uv;
+#endif
+#ifdef UV2
+attribute vec2 uv2;
+#endif
+#ifdef VERTEXCOLOR
+attribute vec4 color;
+#endif
+#ifdef BONES
+attribute vec4 matricesIndices;
+attribute vec4 matricesWeights;
+#endif
+
+// Uniforms
+
+#ifdef INSTANCES
+attribute vec4 world0;
+attribute vec4 world1;
+attribute vec4 world2;
+attribute vec4 world3;
+#else
+uniform mat4 world;
+#endif
+
+uniform mat4 view;
+uniform mat4 viewProjection;
+
+#ifdef BUMP
+varying vec2 vNormalUV;
+uniform mat4 normalMatrix;
+uniform vec2 vNormalInfos;
+#endif
+
+#ifdef BONES
+uniform mat4 mBones[BonesPerMesh];
+#endif
+
+#ifdef POINTSIZE
+uniform float pointSize;
+#endif
+
+// Output
+varying vec3 vPositionW;
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+#ifdef CLIPPLANE
+uniform vec4 vClipPlane;
+varying float fClipDistance;
+#endif
+
+#ifdef FOG
+varying float fFogDistance;
+#endif
+
+#ifdef SHADOWS
+#if defined(SPOTLIGHT0) || defined(DIRLIGHT0)
+uniform mat4 lightMatrix0;
+varying vec4 vPositionFromLight0;
+#endif
+#if defined(SPOTLIGHT1) || defined(DIRLIGHT1)
+uniform mat4 lightMatrix1;
+varying vec4 vPositionFromLight1;
+#endif
+#if defined(SPOTLIGHT2) || defined(DIRLIGHT2)
+uniform mat4 lightMatrix2;
+varying vec4 vPositionFromLight2;
+#endif
+#if defined(SPOTLIGHT3) || defined(DIRLIGHT3)
+uniform mat4 lightMatrix3;
+varying vec4 vPositionFromLight3;
+#endif
+#endif
+
+// Water uniforms
+uniform mat4 worldReflectionViewProjection;
+uniform vec2 windDirection;
+uniform float waveLength;
+uniform float time;
+uniform float windForce;
+uniform float waveHeight;
+uniform float waveSpeed;
+
+// Water varyings
+varying vec3 vPosition;
+varying vec3 vRefractionMapTexCoord;
+varying vec3 vReflectionMapTexCoord;
+
+void main(void) {
+	mat4 finalWorld;
+
+#ifdef INSTANCES
+	finalWorld = mat4(world0, world1, world2, world3);
+#else
+	finalWorld = world;
+#endif
+
+#ifdef BONES
+	mat4 m0 = mBones[int(matricesIndices.x)] * matricesWeights.x;
+	mat4 m1 = mBones[int(matricesIndices.y)] * matricesWeights.y;
+	mat4 m2 = mBones[int(matricesIndices.z)] * matricesWeights.z;
+
+#ifdef BONES4
+	mat4 m3 = mBones[int(matricesIndices.w)] * matricesWeights.w;
+	finalWorld = finalWorld * (m0 + m1 + m2 + m3);
+#else
+	finalWorld = finalWorld * (m0 + m1 + m2);
+#endif 
+
+#endif
+
+	vec4 worldPos = finalWorld * vec4(position, 1.0);
+	vPositionW = vec3(worldPos);
+
+#ifdef NORMAL
+	vNormalW = normalize(vec3(finalWorld * vec4(normal, 0.0)));
+#endif
+
+	// Texture coordinates
+#ifndef UV1
+	vec2 uv = vec2(0., 0.);
+#endif
+#ifndef UV2
+	vec2 uv2 = vec2(0., 0.);
+#endif
+
+#ifdef BUMP
+	if (vNormalInfos.x == 0.)
+	{
+		vNormalUV = vec2(normalMatrix * vec4((uv * 1.0) / waveLength + time * windForce * windDirection, 1.0, 0.0));
+	}
+	else
+	{
+		vNormalUV = vec2(normalMatrix * vec4((uv2 * 1.0) / waveLength + time * windForce * windDirection, 1.0, 0.0));
+	}
+#endif
+
+	// Clip plane
+#ifdef CLIPPLANE
+	fClipDistance = dot(worldPos, vClipPlane);
+#endif
+
+	// Fog
+#ifdef FOG
+	fFogDistance = (view * worldPos).z;
+#endif
+
+	// Shadows
+#ifdef SHADOWS
+#if defined(SPOTLIGHT0) || defined(DIRLIGHT0)
+	vPositionFromLight0 = lightMatrix0 * worldPos;
+#endif
+#if defined(SPOTLIGHT1) || defined(DIRLIGHT1)
+	vPositionFromLight1 = lightMatrix1 * worldPos;
+#endif
+#if defined(SPOTLIGHT2) || defined(DIRLIGHT2)
+	vPositionFromLight2 = lightMatrix2 * worldPos;
+#endif
+#if defined(SPOTLIGHT3) || defined(DIRLIGHT3)
+	vPositionFromLight3 = lightMatrix3 * worldPos;
+#endif
+#endif
+
+	// Vertex color
+#ifdef VERTEXCOLOR
+	vColor = color;
+#endif
+
+	// Point size
+#ifdef POINTSIZE
+	gl_PointSize = pointSize;
+#endif
+
+	vec3 p = position;
+	float newY = (sin(((p.x / 0.05) + time * waveSpeed)) * waveHeight * windDirection.x * 5.0)
+			   + (cos(((p.z / 0.05) +  time * waveSpeed)) * waveHeight * windDirection.y * 5.0);
+	p.y += abs(newY);
+	
+	gl_Position = viewProjection * finalWorld * vec4(p, 1.0);
+
+#ifdef REFLECTION
+	worldPos = viewProjection * finalWorld * vec4(p, 1.0);
+	
+	// Water
+	vPosition = position;
+	
+	vRefractionMapTexCoord.x = 0.5 * (worldPos.w + worldPos.x);
+	vRefractionMapTexCoord.y = 0.5 * (worldPos.w + worldPos.y);
+	vRefractionMapTexCoord.z = worldPos.w;
+	
+	worldPos = worldReflectionViewProjection * vec4(position, 1.0);
+	vReflectionMapTexCoord.x = 0.5 * (worldPos.w + worldPos.x);
+	vReflectionMapTexCoord.y = 0.5 * (worldPos.w + worldPos.y);
+	vReflectionMapTexCoord.z = worldPos.w;
+#endif
+}

+ 14 - 0
materialsLibrary/test/add/addfire.js

@@ -0,0 +1,14 @@
+window.prepareFire = function() {
+    var fire = new BABYLON.FireMaterial("fire", scene);
+    fire.diffuseTexture = new BABYLON.Texture("textures/fire/diffuse.png", scene);
+    fire.distortionTexture = new BABYLON.Texture("textures/fire/distortion.png", scene);
+    fire.opacityTexture = new BABYLON.Texture("textures/fire/opacity.png", scene);
+    
+    registerRangeUI("fire", "speed", 0, 20, function(value) {
+		fire.speed = value;
+	}, function() {
+		return fire.speed;
+	});
+    
+    return fire;
+};

+ 54 - 0
materialsLibrary/test/add/addfur.js

@@ -0,0 +1,54 @@
+window.prepareFur = function() {
+	var fur = new BABYLON.FurMaterial("fur", scene);
+	fur.furLength = 1;
+	fur.furAngle = 0;
+    fur.furColor = new BABYLON.Color3(0.44,0.21,0.02);
+
+
+// fur length
+    registerRangeUI("fur", "Fur length", 0, 15, function(value) {
+        fur.furLength = value;
+    }, function() {
+        return fur.furLength;
+    });
+	
+	// fur angle
+    registerRangeUI("fur", "Fur angle", 0, Math.PI/2, function(value) {
+        fur.furAngle = value;
+    }, function() {
+        return fur.furAngle;
+    });
+    
+    // fur color
+	registerColorPicker("fur", "Fur color", "#703605", function(value) {		
+		fur.furColor.r = value.r/255;
+		fur.furColor.g = value.g/255;
+		fur.furColor.b = value.b/255;
+	}, function() {
+		return fur.furColor;
+	});
+	
+	var DTON = false;
+	registerButtonUI("fur", "Tgl Diffuse Tex", function() {
+		DTON = !DTON;
+		if(DTON) {
+			fur.diffuseTexture = new BABYLON.Texture("textures/leopard_fur.jpg", scene);
+		}
+		else {
+			fur.diffuseTexture = null;
+		}
+	})
+	
+	var HTON = false;
+	registerButtonUI("fur", "Tgl Height Tex", function() {
+		HTON = !HTON;
+		if(HTON) {
+			fur.heightTexture = new BABYLON.Texture("textures/speckles.jpg", scene);
+		}
+		else {
+			fur.heightTexture = null;
+		}
+	})
+    
+    return fur;
+};

+ 19 - 0
materialsLibrary/test/add/addterrain.js

@@ -0,0 +1,19 @@
+window.prepareTerrain = function() {
+    var terrain = new BABYLON.TerrainMaterial("terrain", scene);
+    terrain.specularColor = new BABYLON.Color3(0.5, 0.5, 0.5);
+    terrain.specularPower = 64;
+    terrain.mixTexture = new BABYLON.Texture("textures/mixMap.png", scene);
+    terrain.diffuseTexture1 = new BABYLON.Texture("textures/floor.png", scene);
+    terrain.diffuseTexture2 = new BABYLON.Texture("textures/rock.png", scene);
+    terrain.diffuseTexture3 = new BABYLON.Texture("textures/grass.png", scene);
+    
+    terrain.bumpTexture1 = new BABYLON.Texture("textures/floor_bump.png", scene);
+    terrain.bumpTexture2 = new BABYLON.Texture("textures/rockn.png", scene);
+    terrain.bumpTexture3 = new BABYLON.Texture("textures/grassn.png", scene);
+    
+    terrain.diffuseTexture1.uScale = terrain.diffuseTexture1.vScale = 10;
+    terrain.diffuseTexture2.uScale = terrain.diffuseTexture2.vScale = 10;
+    terrain.diffuseTexture3.uScale = terrain.diffuseTexture3.vScale = 10;
+    
+    return terrain;
+};

Plik diff jest za duży
+ 36966 - 0
materialsLibrary/test/babylon.max.js


+ 25 - 31
materialsLibrary/test/index.html

@@ -11,6 +11,7 @@
     <script src="../dist/babylon.lavaMaterial.js"></script>
 	<script src="../dist/babylon.terrainMaterial.js"></script>
 	<script src="../dist/babylon.pbrMaterial.js"></script>
+	<script src="../dist/babylon.furMaterial.js"></script>
 
 	<style>
 		html, body {
@@ -45,8 +46,13 @@
 	<canvas id="renderCanvas"></canvas>
 
 	<script src="index.js"></script>
-	<script src="add/addpbr.js"></script>
+    <script src="add/addpbr.js"></script>
+    <script src="add/addlava.js"></script>
+    <script src="add/addnormal.js"></script>
 	<script src="add/addwater.js"></script>
+	<script src="add/addfur.js"></script>
+	<script src="add/addterrain.js"></script>
+	<script src="add/addfire.js"></script>
 	
 	<script>
 		if (BABYLON.Engine.isSupported()) {
@@ -81,6 +87,9 @@
 			var knot = BABYLON.Mesh.CreateTorusKnot("knot", 10, 3, 128, 64, 2, 3, scene);
 			knot.setEnabled(false);
 			
+			var heightMap = BABYLON.Mesh.CreateGroundFromHeightMap("heightMap", "textures/heightMap.png", 100, 100, 100, 0, 10, scene, false);
+			heightMap.setEnabled(false);
+			
 			// Skybox
 			var skybox = BABYLON.Mesh.CreateBox("skyBox", 1000.0, scene);
 			var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
@@ -159,20 +168,16 @@
 				std.diffuseTexture.vScale = 5;
 
                 // Lava
-                var lava = new BABYLON.LavaMaterial("lava", scene);
-                lava.diffuseTexture = new BABYLON.Texture("textures/lava/lavatile.jpg", scene);
-                lava.diffuseTexture.uScale = 0.5;
-                lava.diffuseTexture.vScale = 0.5;
-				lava.noiseTexture = new BABYLON.Texture("textures/lava/cloud.png", scene);
-				lava.fogColor = BABYLON.Color3.Black();
-				lava.speed = 2.5;
+                var lava = prepareLava();
 
 				var simple = new BABYLON.SimpleMaterial("simple", scene);
 				simple.diffuseTexture = new BABYLON.Texture("textures/amiga.jpg", scene);
 				simple.diffuseTexture.uScale = 5;
 				simple.diffuseTexture.vScale = 5;
 
-				var normal = new BABYLON.NormalMaterial("normal", scene);
+				var normal = prepareNormal();
+				
+				var fur = prepareFur();
 				
 				var water = prepareWater();
 				water.addToRenderList(skybox);
@@ -180,26 +185,9 @@
 				water.addToRenderList(shadowCaster2);
 				water.addToRenderList(shadowCaster3);
 				
-				var fire = new BABYLON.FireMaterial("fire", scene);
-				fire.diffuseTexture = new BABYLON.Texture("textures/fire/diffuse.png", scene);
-				fire.distortionTexture = new BABYLON.Texture("textures/fire/distortion.png", scene);
-				fire.opacityTexture = new BABYLON.Texture("textures/fire/opacity.png", scene);
-				
-				var terrain = new BABYLON.TerrainMaterial("terrain", scene);
-				terrain.specularColor = new BABYLON.Color3(0.5, 0.5, 0.5);
-				terrain.specularPower = 64;
-				terrain.mixTexture = new BABYLON.Texture("textures/mixMap.png", scene);
-				terrain.diffuseTexture1 = new BABYLON.Texture("textures/grass.png", scene);
-				terrain.diffuseTexture2 = new BABYLON.Texture("textures/rock.png", scene);
-				terrain.diffuseTexture3 = new BABYLON.Texture("textures/floor.png", scene);
+				var fire = prepareFire();
 				
-				terrain.bumpTexture1 = new BABYLON.Texture("textures/grassn.png", scene);
-				terrain.bumpTexture2 = new BABYLON.Texture("textures/rockn.png", scene);
-				terrain.bumpTexture3 = new BABYLON.Texture("textures/floor_bump.png", scene);
-				
-				terrain.diffuseTexture1.uScale = terrain.diffuseTexture1.vScale = 10;
-				terrain.diffuseTexture2.uScale = terrain.diffuseTexture2.vScale = 10;
-				terrain.diffuseTexture3.uScale = terrain.diffuseTexture3.vScale = 10;
+				var terrain = prepareTerrain();
 				
 				var pbr = preparePBR();
 								
@@ -208,7 +196,7 @@
 				sphere.material = std;				
 				sphere.receiveShadows = true;
 
-				gui.add(options, 'material', ['standard', 'simple', 'water', 'fire', 'lava', 'normal', 'terrain', 'pbr']).onFinishChange(function () {
+				gui.add(options, 'material', ['standard', 'simple', 'water', 'fire', 'lava', 'normal', 'terrain', 'pbr', 'fur']).onFinishChange(function () {
 					water.enableRenderTargets(false);
 					
 					switch (options.material) {
@@ -234,7 +222,10 @@
 							break;
 						case "pbr":
 							currentMaterial = pbr;
-							break;													
+							break;
+						case "fur":
+							currentMaterial = fur;
+							break;														
 						default:
 							currentMaterial = std;
 							break;
@@ -245,7 +236,7 @@
 					window.enableMaterial(options.material);
 				});
 
-				gui.add(options, 'mesh', ['sphere', 'knot', 'plane', 'ground', 'rabbit']).onFinishChange(function () {
+				gui.add(options, 'mesh', ['sphere', 'knot', 'plane', 'ground', 'heightMap', 'rabbit']).onFinishChange(function () {
 					currentMesh.setEnabled(false);
 					switch (options.mesh) {
 						case "sphere":
@@ -260,6 +251,9 @@
 						case "ground":
 							currentMesh = ground;
 							break;
+						case "heightMap":
+							currentMesh = heightMap;
+							break;
 						case "rabbit":
 							currentMesh = rabbit;
 							break;

+ 20 - 0
materialsLibrary/test/index.js

@@ -15,6 +15,20 @@ var options = {
 var registeredUIs = {};
 var materialgui;
 
+window.registerColorPicker = function(material, name, color, onChange, onSet) {
+    if (!registeredUIs[material]) {
+        registeredUIs[material] = [];
+    }
+
+    registeredUIs[material].push({
+        name: name,
+        color: "#ff0000",
+        onChange: onChange,
+        onSet: onSet,
+        type: "Color"
+    });
+};
+
 
 window.registerRangeUI = function(material, name, minValue, maxValue, onChange, onSet) {
 	if (!registeredUIs[material]) {
@@ -71,6 +85,12 @@ var setUi = function(ui) {
 			ui.onChange(value);
 		});
 	}
+    else if (ui.type == "Color") {
+        options[ui.name] = ui.onSet();
+        materialgui.addColor(options, ui.name).onChange(function (value) {
+            ui.onChange(value);
+        })
+    }
 	else if (ui.type == "Button") {
 		options[ui.name] = ui.onClick;
 		materialgui.add(options, ui.name);

BIN
materialsLibrary/test/textures/heightMap.png


BIN
materialsLibrary/test/textures/leopard_fur.JPG


BIN
materialsLibrary/test/textures/mixMap.png


BIN
materialsLibrary/test/textures/speckles.jpg


+ 21 - 34
proceduralTexturesLibrary/test/index.html

@@ -160,89 +160,76 @@
 				
 				// Create shaders
 				var std = new BABYLON.StandardMaterial("std", scene);
-				std.diffuseTexture = new BABYLON.Texture("textures/amiga.jpg", scene);
-				std.diffuseTexture.uScale = 5;
-				std.diffuseTexture.vScale = 5;
+				std.specularColor = new BABYLON.Color3(0, 0, 0);
+				
+				var diffuseTexture = new BABYLON.Texture("textures/amiga.jpg", scene);
+				diffuseTexture.uScale = 5;
+				diffuseTexture.vScale = 5;
 
                 // Fire Procedural Texture
                 var firePT = addFirePT();
-				var fireMaterial =  new BABYLON.StandardMaterial("fire", scene);
-				fireMaterial.diffuseTexture = firePT;
 				
 				// Wood Procedural Texture
                 var woodPT = addWoodPT();
-				var woodMaterial =  new BABYLON.StandardMaterial("wood", scene);
-				woodMaterial.diffuseTexture = woodPT;
 				
 				// Cloud Procedural Texture
                 var cloudPT = addCloudPT();
-				var cloudMaterial =  new BABYLON.StandardMaterial("cloud", scene);
-				cloudMaterial.diffuseTexture = cloudPT;
 				
 				// Grass Procedural Texture
                 var grassPT = addGrassPT();
-				var grassMaterial =  new BABYLON.StandardMaterial("grass", scene);
-				grassMaterial.diffuseTexture = grassPT;
 				
 				// Road Procedural Texture
                 var roadPT = addRoadPT();
-				var roadMaterial =  new BABYLON.StandardMaterial("road", scene);
-				roadMaterial.diffuseTexture = roadPT;
 				
 				// Brick Procedural Texture
                 var brickPT = addBrickPT();
-				var brickMaterial =  new BABYLON.StandardMaterial("brick", scene);
-				brickMaterial.diffuseTexture = brickPT;
 				
 				// Marble Procedural Texture
                 var marblePT = addMarblePT();
-				var marbleMaterial =  new BABYLON.StandardMaterial("marble", scene);
-				marbleMaterial.diffuseTexture = marblePT;
 				
 				// Starfield Procedural Texture
                 var starfieldPT = addStarfieldPT();
-				var starfieldMaterial =  new BABYLON.StandardMaterial("starfield", scene);
-			 	starfieldMaterial.diffuseTexture = starfieldPT;
 								
 				// Default to std
-				var currentMaterial = std;
+				var currentTexture = diffuseTexture;
 				sphere.material = std;				
 				sphere.receiveShadows = true;
+				std.diffuseTexture = currentTexture;
 
-				gui.add(options, 'material', ['none', 'fire', 'wood', 'cloud', 'grass', 'road', 'brick', 'marble', 'starfield']).onFinishChange(function () {
-					switch (options.material) {
+				gui.add(options, 'texture', ['default', 'fire', 'wood', 'cloud', 'grass', 'road', 'brick', 'marble', 'starfield']).onFinishChange(function () {
+					switch (options.texture) {
 						case "fire":
-							currentMaterial = fireMaterial;
+							currentTexture = firePT;
 							break;
 						case "wood":
-							currentMaterial = woodMaterial;
+							currentTexture = woodPT;
 							break;
 						case "cloud":
-							currentMaterial = cloudMaterial;
+							currentTexture = cloudPT;
 							break;
 						case "grass":
-							currentMaterial = grassMaterial;
+							currentTexture = grassPT;
 							break;
 						case "road":
-							currentMaterial = roadMaterial;
+							currentTexture = roadPT;
 							break;
 						case "brick":
-							currentMaterial = brickMaterial;
+							currentTexture = brickPT;
 							break;
 						case "marble":
-							currentMaterial = marbleMaterial;
+							currentTexture = marblePT;
 							break;
 						case "starfield":
-							currentMaterial = starfieldMaterial;
+							currentTexture = starfieldPT;
 							break;
 						case "none":
 						default:
-							currentMaterial = std;
+							currentTexture = diffuseTexture;
 							break;
 					}
 
-					currentMesh.material = currentMaterial;
-					window.enableMaterial(options.material);
+					std.diffuseTexture = currentTexture;
+					window.enableTexture(options.texture);
 				});
 
 				gui.add(options, 'mesh', ['sphere', 'knot', 'plane', 'ground', 'rabbit']).onFinishChange(function () {
@@ -266,7 +253,7 @@
 					}
 					currentMesh.setEnabled(true);
 					currentMesh.receiveShadows = true;
-					currentMesh.material = currentMaterial;
+					currentMesh.material = std;
 				});
 
 				var f1 = gui.addFolder('lights');

+ 20 - 20
proceduralTexturesLibrary/test/index.js

@@ -1,7 +1,7 @@
 //UI
 var gui = new dat.GUI();
 var options = {
-	material: "standard",
+	texture: "standard",
 	mesh: "sphere",
 	hemisphericLight: true,
 	pointLight: false,
@@ -13,14 +13,14 @@ var options = {
 }
 
 var registeredUIs = {};
-var materialgui;
+var textureui;
 
-window.registerColorPicker = function(material, name, color, onChange, onSet) {
-    if (!registeredUIs[material]) {
-        registeredUIs[material] = [];
+window.registerColorPicker = function(texture, name, color, onChange, onSet) {
+    if (!registeredUIs[texture]) {
+        registeredUIs[texture] = [];
     }
 
-    registeredUIs[material].push({
+    registeredUIs[texture].push({
         name: name,
         color: "#ff0000",
         onChange: onChange,
@@ -29,12 +29,12 @@ window.registerColorPicker = function(material, name, color, onChange, onSet) {
 };
 
 
-window.registerRangeUI = function(material, name, minValue, maxValue, onChange, onSet) {
-	if (!registeredUIs[material]) {
-		registeredUIs[material] = [];
+window.registerRangeUI = function(texture, name, minValue, maxValue, onChange, onSet) {
+	if (!registeredUIs[texture]) {
+		registeredUIs[texture] = [];
 	}
 	
-	registeredUIs[material].push({
+	registeredUIs[texture].push({
 		name: name,
 		minValue: minValue,
 		maxValue: maxValue,
@@ -47,26 +47,26 @@ var setUi = function(ui) {
 	options[ui.name] = ui.onSet();
 
     if (ui.color) {
-        materialgui.addColor(options, ui.name).onChange(function(value) {
+        textureui.addColor(options, ui.name).onChange(function(value) {
             ui.onChange(value);
         });
     } else {
-        materialgui.add(options, ui.name, ui.minValue, ui.maxValue).onChange(function(value) {
+        textureui.add(options, ui.name, ui.minValue, ui.maxValue).onChange(function(value) {
             ui.onChange(value);
         });
     }
 }
 
-window.enableMaterial = function(material) {
-	if (materialgui) {
-		materialgui.domElement.parentElement.removeChild(materialgui.domElement);	
-		materialgui = null;
+window.enableTexture = function(texture) {
+	if (textureui) {
+		textureui.domElement.parentElement.removeChild(textureui.domElement);	
+		textureui = null;
 	}
 	
-	if (registeredUIs[material]) {
-		materialgui = new dat.GUI();
-		for (var index = 0; index < registeredUIs[material].length; index++) {
-			var ui = registeredUIs[material][index];
+	if (registeredUIs[texture]) {
+		textureui = new dat.GUI();
+		for (var index = 0; index < registeredUIs[texture].length; index++) {
+			var ui = registeredUIs[texture][index];
 			
 			setUi(ui);
 		}	

+ 1 - 91
readme.md

@@ -35,97 +35,7 @@ You can help by testing or contributing to the next version.
  - FBX command line [exporter](https://github.com/BabylonJS/Babylon.js/tree/master/Exporters/FBX) can be used to generate a .babylon file from .FBX file (animations are supported)
 
 ## Features
-- Complete scene graph with lights, cameras, materials and meshes
-- Collisions engine
-- Physics engine (thanks to [oimo.js](https://github.com/lo-th/Oimo.js))
-- Scene picking
-- Antialiasing
-- Animations engine
-- Audio engine
-- Particles Systems
-- Sprites and 2D layers
--  Optimizations engines: 
- - Frustum clipping
- - Sub-meshes clipping
- - Hardware scaling
- - Selection octrees
- - Offline mode via IndexedDB (Assets are saved locally to prevent reloading them)
- - Incremental loading 
- - Binary compressed format
- - Hardware accelerated instances
- - Level of details (LOD)
- - Automatic scene optimizer
- - Debug layer to help you optimize and debug scenes
- - SIMD.js support
- - Collisions can be offloaded on webworkers
- - Merge meshes
-- Standard material is a per pixel material that supports:
- - Diffuse lightning and texture
- - Ambient lightning and texture
- - Specular lightning
- - Opacity texture
- - Reflection texture (Spheric, planar, cubic and projection)
- - Mirror texture
- - Emissive texture
- - Specular texture
- - Bump texture
- - Fresnel term for diffuse, opacity, emissive and reflection
- - Up to 4 lights (points, directionals, spots, hemispherics)
- - Custom materials
- - Custom shaders
- - Skybox
- - Vertex color
- - Bones (Animations and shadows are supported)
- - Procedural textures
--  Special FX
- - Fog
- - Alpha blending
- - Alpha testing
- - Billboarding
- - Fullscreen mode
- - Shadow Maps and Variance Shadow Maps (with support for blurred shadows)
- - Rendering layers
- - Post-processes (blur, refraction, black'n'white, fxaa, customs...)
- - SSAO
- - Volumetric Light Scattering 
- - Depth of field and lens effects
- - HDR rendering pipeline
- - Lens flares
- - Multi-views
- - Edges renderer
--  Textures:
- - Render target textures
- - Dynamic textures (canvas)
- - Video textures
- - Compressed (DDS) textures
- - TGA textures
--  Cameras (Perspective and orthographic):
- - Arc rotate camera
- - Free camera
- - Touch camera
- - Anaglyph camera
- - Virtual Joysticks camera
- - Stereoscopic camera
- - Gamepad camera
- - VR Device Oriention camera
- - WebVR camera
- - Follow camera
--  Meshes: 
- - Mesh cloning
- - Dynamic meshes
- - Height maps
- - Constructive solid geometries
- - Parametric shapes (Ribbon, tube, etc.)
- - Hardware instances
--  Import: 
- - Babylon scene file can be converted from .FBX
- - Exporter for Blender
- - Exporter for Cheetah3d
- - Exporter for 3ds Max
- - Exporter for Unity 5
- - STL importer
- - OBJ importer
- - Assets manager
+To get a complete list of supported features, please visit our [website](babylonjs.com/#specifications).
 
 ## Apache License 2.0 (Apache)
 

+ 88 - 88
src/Actions/babylon.action.ts

@@ -1,89 +1,89 @@
-module BABYLON {
-    export class Action {
-        public trigger: number;
-        public _actionManager: ActionManager;
-
-        private _nextActiveAction: Action;
-        private _child: Action;
-        private _condition: Condition;
-        private _triggerParameter: any;
-
-        constructor(public triggerOptions: any, condition?: Condition) {
-
-            if (triggerOptions.parameter) {
-                this.trigger = triggerOptions.trigger;
-                this._triggerParameter = triggerOptions.parameter;
-            } else {
-                this.trigger = triggerOptions;
-            }
-
-            this._nextActiveAction = this;
-            this._condition = condition;
-        }
-
-        // Methods
-        public _prepare(): void {
-        }
-
-        public getTriggerParameter(): any {
-            return this._triggerParameter;
-        }
-
-        public _executeCurrent(evt: ActionEvent): void {
-            if (this._nextActiveAction._condition) {
-                var condition = this._nextActiveAction._condition;
-                var currentRenderId = this._actionManager.getScene().getRenderId();
-
-                // We cache the current evaluation for the current frame
-                if (condition._evaluationId === currentRenderId) {
-                    if (!condition._currentResult) {
-                        return;
-                    }
-                } else {
-                    condition._evaluationId = currentRenderId;
-
-                    if (!condition.isValid()) {
-                        condition._currentResult = false;
-                        return;
-                    }
-
-                    condition._currentResult = true;
-                }
-            }
-
-            this._nextActiveAction.execute(evt);
-
-            if (this._nextActiveAction._child) {
-
-                if (!this._nextActiveAction._child._actionManager) {
-                    this._nextActiveAction._child._actionManager = this._actionManager;
-                }
-
-                this._nextActiveAction = this._nextActiveAction._child;
-            } else {
-                this._nextActiveAction = this;
-            }
-        }
-
-        public execute(evt: ActionEvent): void {
-
-        }
-
-        public then(action: Action): Action {
-            this._child = action;
-
-            action._actionManager = this._actionManager;
-            action._prepare();
-
-            return action;
-        }
-
-        public _getProperty(propertyPath: string): string {
-            return this._actionManager._getProperty(propertyPath);
-        }
-
-        public _getEffectiveTarget(target: any, propertyPath: string): any {
-            return this._actionManager._getEffectiveTarget(target, propertyPath);
-        }
-    }
+module BABYLON {
+    export class Action {
+        public trigger: number;
+        public _actionManager: ActionManager;
+
+        private _nextActiveAction: Action;
+        private _child: Action;
+        private _condition: Condition;
+        private _triggerParameter: any;
+
+        constructor(public triggerOptions: any, condition?: Condition) {
+
+            if (triggerOptions.parameter) {
+                this.trigger = triggerOptions.trigger;
+                this._triggerParameter = triggerOptions.parameter;
+            } else {
+                this.trigger = triggerOptions;
+            }
+
+            this._nextActiveAction = this;
+            this._condition = condition;
+        }
+
+        // Methods
+        public _prepare(): void {
+        }
+
+        public getTriggerParameter(): any {
+            return this._triggerParameter;
+        }
+
+        public _executeCurrent(evt: ActionEvent): void {
+            if (this._nextActiveAction._condition) {
+                var condition = this._nextActiveAction._condition;
+                var currentRenderId = this._actionManager.getScene().getRenderId();
+
+                // We cache the current evaluation for the current frame
+                if (condition._evaluationId === currentRenderId) {
+                    if (!condition._currentResult) {
+                        return;
+                    }
+                } else {
+                    condition._evaluationId = currentRenderId;
+
+                    if (!condition.isValid()) {
+                        condition._currentResult = false;
+                        return;
+                    }
+
+                    condition._currentResult = true;
+                }
+            }
+
+            this._nextActiveAction.execute(evt);
+
+            if (this._nextActiveAction._child) {
+
+                if (!this._nextActiveAction._child._actionManager) {
+                    this._nextActiveAction._child._actionManager = this._actionManager;
+                }
+
+                this._nextActiveAction = this._nextActiveAction._child;
+            } else {
+                this._nextActiveAction = this;
+            }
+        }
+
+        public execute(evt: ActionEvent): void {
+
+        }
+
+        public then(action: Action): Action {
+            this._child = action;
+
+            action._actionManager = this._actionManager;
+            action._prepare();
+
+            return action;
+        }
+
+        public _getProperty(propertyPath: string): string {
+            return this._actionManager._getProperty(propertyPath);
+        }
+
+        public _getEffectiveTarget(target: any, propertyPath: string): any {
+            return this._actionManager._getEffectiveTarget(target, propertyPath);
+        }
+    }
 }

+ 151 - 0
src/Actions/babylon.actionManager.js

@@ -281,6 +281,157 @@ var BABYLON;
             var properties = propertyPath.split(".");
             return properties[properties.length - 1];
         };
+        ActionManager.Parse = function (parsedActions, object, scene) {
+            var actionManager = new BABYLON.ActionManager(scene);
+            if (object === null)
+                scene.actionManager = actionManager;
+            else
+                object.actionManager = actionManager;
+            // instanciate a new object
+            var instanciate = function (name, params) {
+                var newInstance = Object.create(BABYLON[name].prototype);
+                newInstance.constructor.apply(newInstance, params);
+                return newInstance;
+            };
+            var parseParameter = function (name, value, target, propertyPath) {
+                if (propertyPath === null) {
+                    // String, boolean or float
+                    var floatValue = parseFloat(value);
+                    if (value === "true" || value === "false")
+                        return value === "true";
+                    else
+                        return isNaN(floatValue) ? value : floatValue;
+                }
+                var effectiveTarget = propertyPath.split(".");
+                var values = value.split(",");
+                // Get effective Target
+                for (var i = 0; i < effectiveTarget.length; i++) {
+                    target = target[effectiveTarget[i]];
+                }
+                // Return appropriate value with its type
+                if (typeof (target) === "boolean")
+                    return values[0] === "true";
+                if (typeof (target) === "string")
+                    return values[0];
+                // Parameters with multiple values such as Vector3 etc.
+                var split = new Array();
+                for (var i = 0; i < values.length; i++)
+                    split.push(parseFloat(values[i]));
+                if (target instanceof BABYLON.Vector3)
+                    return BABYLON.Vector3.FromArray(split);
+                if (target instanceof BABYLON.Vector4)
+                    return BABYLON.Vector4.FromArray(split);
+                if (target instanceof BABYLON.Color3)
+                    return BABYLON.Color3.FromArray(split);
+                if (target instanceof BABYLON.Color4)
+                    return BABYLON.Color4.FromArray(split);
+                return parseFloat(values[0]);
+            };
+            // traverse graph per trigger
+            var traverse = function (parsedAction, trigger, condition, action, combineArray) {
+                if (combineArray === void 0) { combineArray = null; }
+                if (parsedAction.detached)
+                    return;
+                var parameters = new Array();
+                var target = null;
+                var propertyPath = null;
+                var combine = parsedAction.combine && parsedAction.combine.length > 0;
+                // Parameters
+                if (parsedAction.type === 2)
+                    parameters.push(actionManager);
+                else
+                    parameters.push(trigger);
+                if (combine) {
+                    var actions = new Array();
+                    for (var j = 0; j < parsedAction.combine.length; j++) {
+                        traverse(parsedAction.combine[j], ActionManager.NothingTrigger, condition, action, actions);
+                    }
+                    parameters.push(actions);
+                }
+                else {
+                    for (var i = 0; i < parsedAction.properties.length; i++) {
+                        var value = parsedAction.properties[i].value;
+                        var name = parsedAction.properties[i].name;
+                        var targetType = parsedAction.properties[i].targetType;
+                        if (name === "target")
+                            if (targetType !== null && targetType === "SceneProperties")
+                                value = target = scene;
+                            else
+                                value = target = scene.getNodeByName(value);
+                        else if (name === "parent")
+                            value = scene.getNodeByName(value);
+                        else if (name === "sound")
+                            value = scene.getSoundByName(value);
+                        else if (name !== "propertyPath") {
+                            if (parsedAction.type === 2 && name === "operator")
+                                value = BABYLON.ValueCondition[value];
+                            else
+                                value = parseParameter(name, value, target, name === "value" ? propertyPath : null);
+                        }
+                        else {
+                            propertyPath = value;
+                        }
+                        parameters.push(value);
+                    }
+                }
+                if (combineArray === null) {
+                    parameters.push(condition);
+                }
+                else {
+                    parameters.push(null);
+                }
+                // If interpolate value action
+                if (parsedAction.name === "InterpolateValueAction") {
+                    var param = parameters[parameters.length - 2];
+                    parameters[parameters.length - 1] = param;
+                    parameters[parameters.length - 2] = condition;
+                }
+                // Action or condition(s) and not CombineAction
+                var newAction = instanciate(parsedAction.name, parameters);
+                if (newAction instanceof BABYLON.Condition && condition !== null) {
+                    var nothing = new BABYLON.DoNothingAction(trigger, condition);
+                    if (action)
+                        action.then(nothing);
+                    else
+                        actionManager.registerAction(nothing);
+                    action = nothing;
+                }
+                if (combineArray === null) {
+                    if (newAction instanceof BABYLON.Condition) {
+                        condition = newAction;
+                        newAction = action;
+                    }
+                    else {
+                        condition = null;
+                        if (action)
+                            action.then(newAction);
+                        else
+                            actionManager.registerAction(newAction);
+                    }
+                }
+                else {
+                    combineArray.push(newAction);
+                }
+                for (var i = 0; i < parsedAction.children.length; i++)
+                    traverse(parsedAction.children[i], trigger, condition, newAction, null);
+            };
+            // triggers
+            for (var i = 0; i < parsedActions.children.length; i++) {
+                var triggerParams;
+                var trigger = parsedActions.children[i];
+                if (trigger.properties.length > 0) {
+                    var param = trigger.properties[0].value;
+                    var value = trigger.properties[0].targetType === null ? param : scene.getMeshByName(param);
+                    triggerParams = { trigger: BABYLON.ActionManager[trigger.name], parameter: value };
+                }
+                else
+                    triggerParams = BABYLON.ActionManager[trigger.name];
+                for (var j = 0; j < trigger.children.length; j++) {
+                    if (!trigger.detached)
+                        traverse(trigger.children[j], triggerParams, null, null);
+                }
+            }
+        };
         // Statics
         ActionManager._NothingTrigger = 0;
         ActionManager._OnPickTrigger = 1;

+ 460 - 280
src/Actions/babylon.actionManager.ts

@@ -1,281 +1,461 @@
-module BABYLON {
-
-    /**
-     * ActionEvent is the event beint sent when an action is triggered.
-     */
-    export class ActionEvent {
-        /**
-         * @constructor
-         * @param source The mesh or sprite that triggered the action.
-         * @param pointerX The X mouse cursor position at the time of the event
-         * @param pointerY The Y mouse cursor position at the time of the event
-         * @param meshUnderPointer The mesh that is currently pointed at (can be null)
-         * @param sourceEvent the original (browser) event that triggered the ActionEvent
-         */
-        constructor(public source: any, public pointerX: number, public pointerY: number, public meshUnderPointer: AbstractMesh, public sourceEvent?: any, public additionalData?: any) {
-
-        }
-
-        /**
-         * Helper function to auto-create an ActionEvent from a source mesh.
-         * @param source The source mesh that triggered the event
-         * @param evt {Event} The original (browser) event
-         */
-        public static CreateNew(source: AbstractMesh, evt?: Event, additionalData?: any): ActionEvent {
-            var scene = source.getScene();
-            return new ActionEvent(source, scene.pointerX, scene.pointerY, scene.meshUnderPointer, evt, additionalData);
-        }
-
-        /**
-         * Helper function to auto-create an ActionEvent from a source mesh.
-         * @param source The source sprite that triggered the event
-         * @param scene Scene associated with the sprite
-         * @param evt {Event} The original (browser) event
-         */
-        public static CreateNewFromSprite(source: Sprite, scene: Scene, evt?: Event, additionalData?: any): ActionEvent {
-            return new ActionEvent(source, scene.pointerX, scene.pointerY, scene.meshUnderPointer, evt, additionalData);
-        }
-
-        /**
-         * Helper function to auto-create an ActionEvent from a scene. If triggered by a mesh use ActionEvent.CreateNew
-         * @param scene the scene where the event occurred
-         * @param evt {Event} The original (browser) event
-         */
-        public static CreateNewFromScene(scene: Scene, evt: Event): ActionEvent {
-            return new ActionEvent(null, scene.pointerX, scene.pointerY, scene.meshUnderPointer, evt);
-        }
-    }
-
-    /**
-     * Action Manager manages all events to be triggered on a given mesh or the global scene.
-     * A single scene can have many Action Managers to handle predefined actions on specific meshes.
-     */
-    export class ActionManager {
-        // Statics
-        private static _NothingTrigger = 0;
-        private static _OnPickTrigger = 1;
-        private static _OnLeftPickTrigger = 2;
-        private static _OnRightPickTrigger = 3;
-        private static _OnCenterPickTrigger = 4;
-        private static _OnPointerOverTrigger = 5;
-        private static _OnPointerOutTrigger = 6;
-        private static _OnEveryFrameTrigger = 7;
-        private static _OnIntersectionEnterTrigger = 8;
-        private static _OnIntersectionExitTrigger = 9;
-        private static _OnKeyDownTrigger = 10;
-        private static _OnKeyUpTrigger = 11;
-        private static _OnPickUpTrigger = 12;
-
-        public static get NothingTrigger(): number {
-            return ActionManager._NothingTrigger;
-        }
-
-        public static get OnPickTrigger(): number {
-            return ActionManager._OnPickTrigger;
-        }
-
-        public static get OnLeftPickTrigger(): number {
-            return ActionManager._OnLeftPickTrigger;
-        }
-
-        public static get OnRightPickTrigger(): number {
-            return ActionManager._OnRightPickTrigger;
-        }
-
-        public static get OnCenterPickTrigger(): number {
-            return ActionManager._OnCenterPickTrigger;
-        }
-
-        public static get OnPointerOverTrigger(): number {
-            return ActionManager._OnPointerOverTrigger;
-        }
-
-        public static get OnPointerOutTrigger(): number {
-            return ActionManager._OnPointerOutTrigger;
-        }
-
-        public static get OnEveryFrameTrigger(): number {
-            return ActionManager._OnEveryFrameTrigger;
-        }
-
-        public static get OnIntersectionEnterTrigger(): number {
-            return ActionManager._OnIntersectionEnterTrigger;
-        }
-
-        public static get OnIntersectionExitTrigger(): number {
-            return ActionManager._OnIntersectionExitTrigger;
-        }
-
-        public static get OnKeyDownTrigger(): number {
-            return ActionManager._OnKeyDownTrigger;
-        }
-
-        public static get OnKeyUpTrigger(): number {
-            return ActionManager._OnKeyUpTrigger;
-        }
-        public static get OnPickUpTrigger(): number {
-            return ActionManager._OnPickUpTrigger;
-        }
-        // Members
-        public actions = new Array<Action>();
-
-        private _scene: Scene;
-
-        constructor(scene: Scene) {
-            this._scene = scene;
-
-            scene._actionManagers.push(this);
-        }
-
-        // Methods
-        public dispose(): void {
-            var index = this._scene._actionManagers.indexOf(this);
-
-            if (index > -1) {
-                this._scene._actionManagers.splice(index, 1);
-            }
-        }
-
-        public getScene(): Scene {
-            return this._scene;
-        }
-
-        /**
-         * Does this action manager handles actions of any of the given triggers
-         * @param {number[]} triggers - the triggers to be tested
-         * @return {boolean} whether one (or more) of the triggers is handeled 
-         */
-        public hasSpecificTriggers(triggers: number[]): boolean {
-            for (var index = 0; index < this.actions.length; index++) {
-                var action = this.actions[index];
-
-                if (triggers.indexOf(action.trigger) > -1) {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-
-        /**
-         * Does this action manager handles actions of a given trigger
-         * @param {number} trigger - the trigger to be tested
-         * @return {boolean} whether the trigger is handeled 
-         */
-        public hasSpecificTrigger(trigger: number): boolean {
-            for (var index = 0; index < this.actions.length; index++) {
-                var action = this.actions[index];
-
-                if (action.trigger === trigger) {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-
-        /**
-         * Does this action manager has pointer triggers
-         * @return {boolean} whether or not it has pointer triggers
-         */
-        public get hasPointerTriggers(): boolean {
-            for (var index = 0; index < this.actions.length; index++) {
-                var action = this.actions[index];
-
-                if (action.trigger >= ActionManager._OnPickTrigger && action.trigger <= ActionManager._OnPointerOutTrigger) {
-                    return true;
-                }
-                if (action.trigger === ActionManager._OnPickUpTrigger) {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-
-        /**
-         * Does this action manager has pick triggers
-         * @return {boolean} whether or not it has pick triggers
-         */
-        public get hasPickTriggers(): boolean {
-            for (var index = 0; index < this.actions.length; index++) {
-                var action = this.actions[index];
-
-                if (action.trigger >= ActionManager._OnPickTrigger && action.trigger <= ActionManager._OnCenterPickTrigger) {
-                    return true;
-                }
-                if (action.trigger === ActionManager._OnPickUpTrigger) {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-
-        /**
-         * Registers an action to this action manager
-         * @param {BABYLON.Action} action - the action to be registered
-         * @return {BABYLON.Action} the action amended (prepared) after registration
-         */
-        public registerAction(action: Action): Action {
-            if (action.trigger === ActionManager.OnEveryFrameTrigger) {
-                if (this.getScene().actionManager !== this) {
-                    Tools.Warn("OnEveryFrameTrigger can only be used with scene.actionManager");
-                    return null;
-                }
-            }
-
-
-            this.actions.push(action);
-
-            action._actionManager = this;
-            action._prepare();
-
-            return action;
-        }
-
-        /**
-         * Process a specific trigger
-         * @param {number} trigger - the trigger to process
-         * @param evt {BABYLON.ActionEvent} the event details to be processed
-         */
-        public processTrigger(trigger: number, evt: ActionEvent): void {
-            for (var index = 0; index < this.actions.length; index++) {
-                var action = this.actions[index];
-
-                if (action.trigger === trigger) {
-                    if (trigger === ActionManager.OnKeyUpTrigger
-                        || trigger === ActionManager.OnKeyDownTrigger) {
-                        var parameter = action.getTriggerParameter();
-
-                        if (parameter) {
-                            var unicode = evt.sourceEvent.charCode ? evt.sourceEvent.charCode : evt.sourceEvent.keyCode;
-                            var actualkey = String.fromCharCode(unicode).toLowerCase();
-                            if (actualkey !== parameter.toLowerCase()) {
-                                continue;
-                            }
-                        }
-                    }
-
-                    action._executeCurrent(evt);
-                }
-            }
-        }
-
-        public _getEffectiveTarget(target: any, propertyPath: string): any {
-            var properties = propertyPath.split(".");
-
-            for (var index = 0; index < properties.length - 1; index++) {
-                target = target[properties[index]];
-            }
-
-            return target;
-        }
-
-        public _getProperty(propertyPath: string): string {
-            var properties = propertyPath.split(".");
-
-            return properties[properties.length - 1];
-        }
-    }
+module BABYLON {
+
+    /**
+     * ActionEvent is the event beint sent when an action is triggered.
+     */
+    export class ActionEvent {
+        /**
+         * @constructor
+         * @param source The mesh or sprite that triggered the action.
+         * @param pointerX The X mouse cursor position at the time of the event
+         * @param pointerY The Y mouse cursor position at the time of the event
+         * @param meshUnderPointer The mesh that is currently pointed at (can be null)
+         * @param sourceEvent the original (browser) event that triggered the ActionEvent
+         */
+        constructor(public source: any, public pointerX: number, public pointerY: number, public meshUnderPointer: AbstractMesh, public sourceEvent?: any, public additionalData?: any) {
+
+        }
+
+        /**
+         * Helper function to auto-create an ActionEvent from a source mesh.
+         * @param source The source mesh that triggered the event
+         * @param evt {Event} The original (browser) event
+         */
+        public static CreateNew(source: AbstractMesh, evt?: Event, additionalData?: any): ActionEvent {
+            var scene = source.getScene();
+            return new ActionEvent(source, scene.pointerX, scene.pointerY, scene.meshUnderPointer, evt, additionalData);
+        }
+
+        /**
+         * Helper function to auto-create an ActionEvent from a source mesh.
+         * @param source The source sprite that triggered the event
+         * @param scene Scene associated with the sprite
+         * @param evt {Event} The original (browser) event
+         */
+        public static CreateNewFromSprite(source: Sprite, scene: Scene, evt?: Event, additionalData?: any): ActionEvent {
+            return new ActionEvent(source, scene.pointerX, scene.pointerY, scene.meshUnderPointer, evt, additionalData);
+        }
+
+        /**
+         * Helper function to auto-create an ActionEvent from a scene. If triggered by a mesh use ActionEvent.CreateNew
+         * @param scene the scene where the event occurred
+         * @param evt {Event} The original (browser) event
+         */
+        public static CreateNewFromScene(scene: Scene, evt: Event): ActionEvent {
+            return new ActionEvent(null, scene.pointerX, scene.pointerY, scene.meshUnderPointer, evt);
+        }
+    }
+
+    /**
+     * Action Manager manages all events to be triggered on a given mesh or the global scene.
+     * A single scene can have many Action Managers to handle predefined actions on specific meshes.
+     */
+    export class ActionManager {
+        // Statics
+        private static _NothingTrigger = 0;
+        private static _OnPickTrigger = 1;
+        private static _OnLeftPickTrigger = 2;
+        private static _OnRightPickTrigger = 3;
+        private static _OnCenterPickTrigger = 4;
+        private static _OnPointerOverTrigger = 5;
+        private static _OnPointerOutTrigger = 6;
+        private static _OnEveryFrameTrigger = 7;
+        private static _OnIntersectionEnterTrigger = 8;
+        private static _OnIntersectionExitTrigger = 9;
+        private static _OnKeyDownTrigger = 10;
+        private static _OnKeyUpTrigger = 11;
+        private static _OnPickUpTrigger = 12;
+
+        public static get NothingTrigger(): number {
+            return ActionManager._NothingTrigger;
+        }
+
+        public static get OnPickTrigger(): number {
+            return ActionManager._OnPickTrigger;
+        }
+
+        public static get OnLeftPickTrigger(): number {
+            return ActionManager._OnLeftPickTrigger;
+        }
+
+        public static get OnRightPickTrigger(): number {
+            return ActionManager._OnRightPickTrigger;
+        }
+
+        public static get OnCenterPickTrigger(): number {
+            return ActionManager._OnCenterPickTrigger;
+        }
+
+        public static get OnPointerOverTrigger(): number {
+            return ActionManager._OnPointerOverTrigger;
+        }
+
+        public static get OnPointerOutTrigger(): number {
+            return ActionManager._OnPointerOutTrigger;
+        }
+
+        public static get OnEveryFrameTrigger(): number {
+            return ActionManager._OnEveryFrameTrigger;
+        }
+
+        public static get OnIntersectionEnterTrigger(): number {
+            return ActionManager._OnIntersectionEnterTrigger;
+        }
+
+        public static get OnIntersectionExitTrigger(): number {
+            return ActionManager._OnIntersectionExitTrigger;
+        }
+
+        public static get OnKeyDownTrigger(): number {
+            return ActionManager._OnKeyDownTrigger;
+        }
+
+        public static get OnKeyUpTrigger(): number {
+            return ActionManager._OnKeyUpTrigger;
+        }
+        public static get OnPickUpTrigger(): number {
+            return ActionManager._OnPickUpTrigger;
+        }
+        // Members
+        public actions = new Array<Action>();
+
+        private _scene: Scene;
+
+        constructor(scene: Scene) {
+            this._scene = scene;
+
+            scene._actionManagers.push(this);
+        }
+
+        // Methods
+        public dispose(): void {
+            var index = this._scene._actionManagers.indexOf(this);
+
+            if (index > -1) {
+                this._scene._actionManagers.splice(index, 1);
+            }
+        }
+
+        public getScene(): Scene {
+            return this._scene;
+        }
+
+        /**
+         * Does this action manager handles actions of any of the given triggers
+         * @param {number[]} triggers - the triggers to be tested
+         * @return {boolean} whether one (or more) of the triggers is handeled 
+         */
+        public hasSpecificTriggers(triggers: number[]): boolean {
+            for (var index = 0; index < this.actions.length; index++) {
+                var action = this.actions[index];
+
+                if (triggers.indexOf(action.trigger) > -1) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        /**
+         * Does this action manager handles actions of a given trigger
+         * @param {number} trigger - the trigger to be tested
+         * @return {boolean} whether the trigger is handeled 
+         */
+        public hasSpecificTrigger(trigger: number): boolean {
+            for (var index = 0; index < this.actions.length; index++) {
+                var action = this.actions[index];
+
+                if (action.trigger === trigger) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        /**
+         * Does this action manager has pointer triggers
+         * @return {boolean} whether or not it has pointer triggers
+         */
+        public get hasPointerTriggers(): boolean {
+            for (var index = 0; index < this.actions.length; index++) {
+                var action = this.actions[index];
+
+                if (action.trigger >= ActionManager._OnPickTrigger && action.trigger <= ActionManager._OnPointerOutTrigger) {
+                    return true;
+                }
+                if (action.trigger === ActionManager._OnPickUpTrigger) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        /**
+         * Does this action manager has pick triggers
+         * @return {boolean} whether or not it has pick triggers
+         */
+        public get hasPickTriggers(): boolean {
+            for (var index = 0; index < this.actions.length; index++) {
+                var action = this.actions[index];
+
+                if (action.trigger >= ActionManager._OnPickTrigger && action.trigger <= ActionManager._OnCenterPickTrigger) {
+                    return true;
+                }
+                if (action.trigger === ActionManager._OnPickUpTrigger) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        /**
+         * Registers an action to this action manager
+         * @param {BABYLON.Action} action - the action to be registered
+         * @return {BABYLON.Action} the action amended (prepared) after registration
+         */
+        public registerAction(action: Action): Action {
+            if (action.trigger === ActionManager.OnEveryFrameTrigger) {
+                if (this.getScene().actionManager !== this) {
+                    Tools.Warn("OnEveryFrameTrigger can only be used with scene.actionManager");
+                    return null;
+                }
+            }
+
+
+            this.actions.push(action);
+
+            action._actionManager = this;
+            action._prepare();
+
+            return action;
+        }
+
+        /**
+         * Process a specific trigger
+         * @param {number} trigger - the trigger to process
+         * @param evt {BABYLON.ActionEvent} the event details to be processed
+         */
+        public processTrigger(trigger: number, evt: ActionEvent): void {
+            for (var index = 0; index < this.actions.length; index++) {
+                var action = this.actions[index];
+
+                if (action.trigger === trigger) {
+                    if (trigger === ActionManager.OnKeyUpTrigger
+                        || trigger === ActionManager.OnKeyDownTrigger) {
+                        var parameter = action.getTriggerParameter();
+
+                        if (parameter) {
+                            var unicode = evt.sourceEvent.charCode ? evt.sourceEvent.charCode : evt.sourceEvent.keyCode;
+                            var actualkey = String.fromCharCode(unicode).toLowerCase();
+                            if (actualkey !== parameter.toLowerCase()) {
+                                continue;
+                            }
+                        }
+                    }
+
+                    action._executeCurrent(evt);
+                }
+            }
+        }
+
+        public _getEffectiveTarget(target: any, propertyPath: string): any {
+            var properties = propertyPath.split(".");
+
+            for (var index = 0; index < properties.length - 1; index++) {
+                target = target[properties[index]];
+            }
+
+            return target;
+        }
+
+        public _getProperty(propertyPath: string): string {
+            var properties = propertyPath.split(".");
+
+            return properties[properties.length - 1];
+        }
+
+        public static Parse(parsedActions: any, object: AbstractMesh, scene: Scene) {
+            var actionManager = new BABYLON.ActionManager(scene);
+            if (object === null)
+                scene.actionManager = actionManager;
+            else
+                object.actionManager = actionManager;
+
+            // instanciate a new object
+            var instanciate = (name: any, params: Array<any>): any => {
+                var newInstance: Object = Object.create(BABYLON[name].prototype);
+                newInstance.constructor.apply(newInstance, params);
+                return newInstance;
+            };
+
+            var parseParameter = (name: string, value: string, target: any, propertyPath: string): any => {
+                if (propertyPath === null) {
+                    // String, boolean or float
+                    var floatValue = parseFloat(value);
+
+                    if (value === "true" || value === "false")
+                        return value === "true";
+                    else
+                        return isNaN(floatValue) ? value : floatValue;
+                }
+
+                var effectiveTarget = propertyPath.split(".");
+                var values = value.split(",");
+
+                // Get effective Target
+                for (var i = 0; i < effectiveTarget.length; i++) {
+                    target = target[effectiveTarget[i]];
+                }
+
+                // Return appropriate value with its type
+                if (typeof (target) === "boolean")
+                    return values[0] === "true";
+
+                if (typeof (target) === "string")
+                    return values[0];
+
+                // Parameters with multiple values such as Vector3 etc.
+                var split = new Array<number>();
+                for (var i = 0; i < values.length; i++)
+                    split.push(parseFloat(values[i]));
+
+                if (target instanceof Vector3)
+                    return Vector3.FromArray(split);
+
+                if (target instanceof Vector4)
+                    return Vector4.FromArray(split);
+
+                if (target instanceof Color3)
+                    return Color3.FromArray(split);
+
+                if (target instanceof Color4)
+                    return Color4.FromArray(split);
+
+                return parseFloat(values[0]);
+            };
+
+            // traverse graph per trigger
+            var traverse = (parsedAction: any, trigger: any, condition: Condition, action: Action, combineArray: Array<Action> = null) => {
+                if (parsedAction.detached)
+                    return;
+
+                var parameters = new Array<any>();
+                var target: any = null;
+                var propertyPath: string = null;
+                var combine = parsedAction.combine && parsedAction.combine.length > 0;
+
+                // Parameters
+                if (parsedAction.type === 2)
+                    parameters.push(actionManager);
+                else
+                    parameters.push(trigger);
+
+                if (combine) {
+                    var actions = new Array<Action>();
+                    for (var j = 0; j < parsedAction.combine.length; j++) {
+                        traverse(parsedAction.combine[j], ActionManager.NothingTrigger, condition, action, actions);
+                    }
+                    parameters.push(actions);
+                }
+                else {
+                    for (var i = 0; i < parsedAction.properties.length; i++) {
+                        var value = parsedAction.properties[i].value;
+                        var name = parsedAction.properties[i].name;
+                        var targetType = parsedAction.properties[i].targetType;
+
+                        if (name === "target")
+                            if (targetType !== null && targetType === "SceneProperties")
+                                value = target = scene;
+                            else
+                                value = target = scene.getNodeByName(value);
+                        else if (name === "parent")
+                            value = scene.getNodeByName(value);
+                        else if (name === "sound")
+                            value = scene.getSoundByName(value);
+                        else if (name !== "propertyPath") {
+                            if (parsedAction.type === 2 && name === "operator")
+                                value = ValueCondition[value];
+                            else
+                                value = parseParameter(name, value, target, name === "value" ? propertyPath : null);
+                        } else {
+                            propertyPath = value;
+                        }
+
+                        parameters.push(value);
+                    }
+                }
+
+                if (combineArray === null) {
+                    parameters.push(condition);
+                }
+                else {
+                    parameters.push(null);
+                }
+
+                // If interpolate value action
+                if (parsedAction.name === "InterpolateValueAction") {
+                    var param = parameters[parameters.length - 2];
+                    parameters[parameters.length - 1] = param;
+                    parameters[parameters.length - 2] = condition;
+                }
+
+                // Action or condition(s) and not CombineAction
+                var newAction = instanciate(parsedAction.name, parameters);
+
+                if (newAction instanceof Condition && condition !== null) {
+                    var nothing = new DoNothingAction(trigger, condition);
+
+                    if (action)
+                        action.then(nothing);
+                    else
+                        actionManager.registerAction(nothing);
+
+                    action = nothing;
+                }
+
+                if (combineArray === null) {
+                    if (newAction instanceof Condition) {
+                        condition = newAction;
+                        newAction = action;
+                    } else {
+                        condition = null;
+                        if (action)
+                            action.then(newAction);
+                        else
+                            actionManager.registerAction(newAction);
+                    }
+                }
+                else {
+                    combineArray.push(newAction);
+                }
+
+                for (var i = 0; i < parsedAction.children.length; i++)
+                    traverse(parsedAction.children[i], trigger, condition, newAction, null);
+            };
+
+            // triggers
+            for (var i = 0; i < parsedActions.children.length; i++) {
+                var triggerParams: any;
+                var trigger = parsedActions.children[i];
+
+                if (trigger.properties.length > 0) {
+                    var param = trigger.properties[0].value;
+                    var value = trigger.properties[0].targetType === null ? param : scene.getMeshByName(param);
+                    triggerParams = { trigger: BABYLON.ActionManager[trigger.name], parameter: value };
+                }
+                else
+                    triggerParams = BABYLON.ActionManager[trigger.name];
+
+                for (var j = 0; j < trigger.children.length; j++) {
+                    if (!trigger.detached)
+                        traverse(trigger.children[j], triggerParams, null, null);
+                }
+            }
+        }
+
+    }
 } 

+ 115 - 115
src/Actions/babylon.condition.ts

@@ -1,116 +1,116 @@
-module BABYLON {
-    export class Condition {
-        public _actionManager: ActionManager;
-
-        public _evaluationId: number;
-        public _currentResult: boolean;
-
-        constructor(actionManager: ActionManager) {
-            this._actionManager = actionManager;
-        }
-
-        public isValid(): boolean {
-            return true;
-        }
-
-        public _getProperty(propertyPath: string): string {
-            return this._actionManager._getProperty(propertyPath);
-        }
-
-        public _getEffectiveTarget(target: any, propertyPath: string): any {
-            return this._actionManager._getEffectiveTarget(target, propertyPath);
-        }
-    }
-
-    export class ValueCondition extends Condition {
-        // Statics
-        private static _IsEqual = 0;
-        private static _IsDifferent = 1;
-        private static _IsGreater = 2;
-        private static _IsLesser = 3;
-
-        public static get IsEqual(): number {
-            return ValueCondition._IsEqual;
-        }
-
-        public static get IsDifferent(): number {
-            return ValueCondition._IsDifferent;
-        }
-
-        public static get IsGreater(): number {
-            return ValueCondition._IsGreater;
-        }
-
-        public static get IsLesser(): number {
-            return ValueCondition._IsLesser;
-        }
-
-        // Members
-        public _actionManager: ActionManager;
-
-        private _target: any;
-        private _property: string;
-
-        constructor(actionManager: ActionManager, target: any, public propertyPath: string, public value: any, public operator: number = ValueCondition.IsEqual) {
-            super(actionManager);
-
-            this._target = this._getEffectiveTarget(target, this.propertyPath);
-            this._property = this._getProperty(this.propertyPath);
-        }
-
-        // Methods
-        public isValid(): boolean {
-            switch (this.operator) {
-                case ValueCondition.IsGreater:
-                    return this._target[this._property] > this.value;
-                case ValueCondition.IsLesser:
-                    return this._target[this._property] < this.value;
-                case ValueCondition.IsEqual:
-                case ValueCondition.IsDifferent:
-                    var check: boolean;
-
-                    if (this.value.equals) {
-                        check = this.value.equals(this._target[this._property]);
-                    } else {
-                        check = this.value === this._target[this._property];
-                    }
-                    return this.operator === ValueCondition.IsEqual ? check : !check;
-            }
-
-            return false;
-        }
-    }
-
-    export class PredicateCondition extends Condition {
-        // Members
-        public _actionManager: ActionManager;
-
-
-        constructor(actionManager: ActionManager, public predicate: () => boolean) {
-            super(actionManager);
-        }
-
-        public isValid(): boolean {
-            return this.predicate();
-        }
-    }
-
-    export class StateCondition extends Condition {
-        // Members
-        public _actionManager: ActionManager;
-
-        private _target: any;
-
-        constructor(actionManager: ActionManager, target: any, public value: string) {
-            super(actionManager);
-
-            this._target = target;
-        }
-
-        // Methods
-        public isValid(): boolean {
-            return this._target.state === this.value;
-        }
-    }
-
+module BABYLON {
+    export class Condition {
+        public _actionManager: ActionManager;
+
+        public _evaluationId: number;
+        public _currentResult: boolean;
+
+        constructor(actionManager: ActionManager) {
+            this._actionManager = actionManager;
+        }
+
+        public isValid(): boolean {
+            return true;
+        }
+
+        public _getProperty(propertyPath: string): string {
+            return this._actionManager._getProperty(propertyPath);
+        }
+
+        public _getEffectiveTarget(target: any, propertyPath: string): any {
+            return this._actionManager._getEffectiveTarget(target, propertyPath);
+        }
+    }
+
+    export class ValueCondition extends Condition {
+        // Statics
+        private static _IsEqual = 0;
+        private static _IsDifferent = 1;
+        private static _IsGreater = 2;
+        private static _IsLesser = 3;
+
+        public static get IsEqual(): number {
+            return ValueCondition._IsEqual;
+        }
+
+        public static get IsDifferent(): number {
+            return ValueCondition._IsDifferent;
+        }
+
+        public static get IsGreater(): number {
+            return ValueCondition._IsGreater;
+        }
+
+        public static get IsLesser(): number {
+            return ValueCondition._IsLesser;
+        }
+
+        // Members
+        public _actionManager: ActionManager;
+
+        private _target: any;
+        private _property: string;
+
+        constructor(actionManager: ActionManager, target: any, public propertyPath: string, public value: any, public operator: number = ValueCondition.IsEqual) {
+            super(actionManager);
+
+            this._target = this._getEffectiveTarget(target, this.propertyPath);
+            this._property = this._getProperty(this.propertyPath);
+        }
+
+        // Methods
+        public isValid(): boolean {
+            switch (this.operator) {
+                case ValueCondition.IsGreater:
+                    return this._target[this._property] > this.value;
+                case ValueCondition.IsLesser:
+                    return this._target[this._property] < this.value;
+                case ValueCondition.IsEqual:
+                case ValueCondition.IsDifferent:
+                    var check: boolean;
+
+                    if (this.value.equals) {
+                        check = this.value.equals(this._target[this._property]);
+                    } else {
+                        check = this.value === this._target[this._property];
+                    }
+                    return this.operator === ValueCondition.IsEqual ? check : !check;
+            }
+
+            return false;
+        }
+    }
+
+    export class PredicateCondition extends Condition {
+        // Members
+        public _actionManager: ActionManager;
+
+
+        constructor(actionManager: ActionManager, public predicate: () => boolean) {
+            super(actionManager);
+        }
+
+        public isValid(): boolean {
+            return this.predicate();
+        }
+    }
+
+    export class StateCondition extends Condition {
+        // Members
+        public _actionManager: ActionManager;
+
+        private _target: any;
+
+        constructor(actionManager: ActionManager, target: any, public value: string) {
+            super(actionManager);
+
+            this._target = target;
+        }
+
+        // Methods
+        public isValid(): boolean {
+            return this._target.state === this.value;
+        }
+    }
+
 }

+ 207 - 207
src/Actions/babylon.directActions.ts

@@ -1,208 +1,208 @@
-module BABYLON {
-    export class SwitchBooleanAction extends Action {
-        private _target: any;
-        private _property: string;
-
-        constructor(triggerOptions: any, target: any, public propertyPath: string, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-        }
-
-        public _prepare(): void {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
-            this._property = this._getProperty(this.propertyPath);
-        }
-
-        public execute(): void {
-            this._target[this._property] = !this._target[this._property];
-        }
-    }
-
-    export class SetStateAction extends Action {
-        private _target: any;
-
-        constructor(triggerOptions: any, target: any, public value: string, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-        }
-
-        public execute(): void {
-            this._target.state = this.value;
-        }
-    }
-
-    export class SetValueAction extends Action {
-        private _target: any;
-        private _property: string;
-
-        constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-        }
-
-        public _prepare(): void {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
-            this._property = this._getProperty(this.propertyPath);
-        }
-
-        public execute(): void {
-            this._target[this._property] = this.value;
-        }
-    }
-
-    export class IncrementValueAction extends Action {
-        private _target: any;
-        private _property: string;
-
-        constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-        }
-
-        public _prepare(): void {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
-            this._property = this._getProperty(this.propertyPath);
-
-            if (typeof this._target[this._property] !== "number") {
-                Tools.Warn("Warning: IncrementValueAction can only be used with number values");
-            }
-        }
-
-        public execute(): void {
-            this._target[this._property] += this.value;
-        }
-    }
-
-    export class PlayAnimationAction extends Action {
-        private _target: any;
-
-        constructor(triggerOptions: any, target: any, public from: number, public to: number, public loop?: boolean, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-        }
-
-        public _prepare(): void {
-        }
-
-        public execute(): void {
-            var scene = this._actionManager.getScene();
-            scene.beginAnimation(this._target, this.from, this.to, this.loop);
-        }
-    }
-
-    export class StopAnimationAction extends Action {
-        private _target: any;
-
-        constructor(triggerOptions: any, target: any, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-        }
-
-        public _prepare(): void {           
-        }
-
-        public execute(): void {
-            var scene = this._actionManager.getScene();
-            scene.stopAnimation(this._target);
-        }
-    }
-
-    export class DoNothingAction extends Action {
-        constructor(triggerOptions: any = ActionManager.NothingTrigger, condition?: Condition) {
-            super(triggerOptions, condition);
-        }
-
-        public execute(): void {
-        }
-    }
-
-    export class CombineAction extends Action {
-        constructor(triggerOptions: any, public children: Action[], condition?: Condition) {
-            super(triggerOptions, condition);
-        }
-
-        public _prepare(): void {
-            for (var index = 0; index < this.children.length; index++) {
-                this.children[index]._actionManager = this._actionManager;
-                this.children[index]._prepare();
-            }
-        }
-
-        public execute(evt: ActionEvent): void {
-            for (var index = 0; index < this.children.length; index++) {
-                this.children[index].execute(evt);
-            }
-        }
-    }
-
-    export class ExecuteCodeAction extends Action {
-        constructor(triggerOptions: any, public func: (evt: ActionEvent) => void, condition?: Condition) {
-            super(triggerOptions, condition);
-        }
-
-        public execute(evt: ActionEvent): void {
-            this.func(evt);
-        }
-    }
-
-    export class SetParentAction extends Action {
-        private _parent: any;
-        private _target: any;
-
-        constructor(triggerOptions: any, target: any, parent: any, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._target = target;
-            this._parent = parent;
-        }
-
-        public _prepare(): void {
-        }
-
-        public execute(): void {
-            if (this._target.parent === this._parent) {
-                return;
-            }
-
-            var invertParentWorldMatrix = this._parent.getWorldMatrix().clone();
-            invertParentWorldMatrix.invert();
-
-            this._target.position = Vector3.TransformCoordinates(this._target.position, invertParentWorldMatrix);
-
-            this._target.parent = this._parent;
-        }
-    }
-
-    export class PlaySoundAction extends Action {
-        private _sound: Sound;
-
-        constructor(triggerOptions: any, sound: Sound, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._sound = sound;
-        }
-
-        public _prepare(): void {
-        }
-
-        public execute(): void {
-            if (this._sound !== undefined)
-                this._sound.play();
-        }
-    }
-
-    export class StopSoundAction extends Action {
-        private _sound: Sound;
-
-        constructor(triggerOptions: any, sound: Sound, condition?: Condition) {
-            super(triggerOptions, condition);
-            this._sound = sound;
-        }
-
-        public _prepare(): void {
-        }
-
-        public execute(): void {
-            if (this._sound !== undefined)
-                this._sound.stop();
-        }
-    }
+module BABYLON {
+    export class SwitchBooleanAction extends Action {
+        private _target: any;
+        private _property: string;
+
+        constructor(triggerOptions: any, target: any, public propertyPath: string, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+        }
+
+        public _prepare(): void {
+            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._property = this._getProperty(this.propertyPath);
+        }
+
+        public execute(): void {
+            this._target[this._property] = !this._target[this._property];
+        }
+    }
+
+    export class SetStateAction extends Action {
+        private _target: any;
+
+        constructor(triggerOptions: any, target: any, public value: string, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+        }
+
+        public execute(): void {
+            this._target.state = this.value;
+        }
+    }
+
+    export class SetValueAction extends Action {
+        private _target: any;
+        private _property: string;
+
+        constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+        }
+
+        public _prepare(): void {
+            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._property = this._getProperty(this.propertyPath);
+        }
+
+        public execute(): void {
+            this._target[this._property] = this.value;
+        }
+    }
+
+    export class IncrementValueAction extends Action {
+        private _target: any;
+        private _property: string;
+
+        constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+        }
+
+        public _prepare(): void {
+            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._property = this._getProperty(this.propertyPath);
+
+            if (typeof this._target[this._property] !== "number") {
+                Tools.Warn("Warning: IncrementValueAction can only be used with number values");
+            }
+        }
+
+        public execute(): void {
+            this._target[this._property] += this.value;
+        }
+    }
+
+    export class PlayAnimationAction extends Action {
+        private _target: any;
+
+        constructor(triggerOptions: any, target: any, public from: number, public to: number, public loop?: boolean, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+        }
+
+        public _prepare(): void {
+        }
+
+        public execute(): void {
+            var scene = this._actionManager.getScene();
+            scene.beginAnimation(this._target, this.from, this.to, this.loop);
+        }
+    }
+
+    export class StopAnimationAction extends Action {
+        private _target: any;
+
+        constructor(triggerOptions: any, target: any, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+        }
+
+        public _prepare(): void {           
+        }
+
+        public execute(): void {
+            var scene = this._actionManager.getScene();
+            scene.stopAnimation(this._target);
+        }
+    }
+
+    export class DoNothingAction extends Action {
+        constructor(triggerOptions: any = ActionManager.NothingTrigger, condition?: Condition) {
+            super(triggerOptions, condition);
+        }
+
+        public execute(): void {
+        }
+    }
+
+    export class CombineAction extends Action {
+        constructor(triggerOptions: any, public children: Action[], condition?: Condition) {
+            super(triggerOptions, condition);
+        }
+
+        public _prepare(): void {
+            for (var index = 0; index < this.children.length; index++) {
+                this.children[index]._actionManager = this._actionManager;
+                this.children[index]._prepare();
+            }
+        }
+
+        public execute(evt: ActionEvent): void {
+            for (var index = 0; index < this.children.length; index++) {
+                this.children[index].execute(evt);
+            }
+        }
+    }
+
+    export class ExecuteCodeAction extends Action {
+        constructor(triggerOptions: any, public func: (evt: ActionEvent) => void, condition?: Condition) {
+            super(triggerOptions, condition);
+        }
+
+        public execute(evt: ActionEvent): void {
+            this.func(evt);
+        }
+    }
+
+    export class SetParentAction extends Action {
+        private _parent: any;
+        private _target: any;
+
+        constructor(triggerOptions: any, target: any, parent: any, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._target = target;
+            this._parent = parent;
+        }
+
+        public _prepare(): void {
+        }
+
+        public execute(): void {
+            if (this._target.parent === this._parent) {
+                return;
+            }
+
+            var invertParentWorldMatrix = this._parent.getWorldMatrix().clone();
+            invertParentWorldMatrix.invert();
+
+            this._target.position = Vector3.TransformCoordinates(this._target.position, invertParentWorldMatrix);
+
+            this._target.parent = this._parent;
+        }
+    }
+
+    export class PlaySoundAction extends Action {
+        private _sound: Sound;
+
+        constructor(triggerOptions: any, sound: Sound, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._sound = sound;
+        }
+
+        public _prepare(): void {
+        }
+
+        public execute(): void {
+            if (this._sound !== undefined)
+                this._sound.play();
+        }
+    }
+
+    export class StopSoundAction extends Action {
+        private _sound: Sound;
+
+        constructor(triggerOptions: any, sound: Sound, condition?: Condition) {
+            super(triggerOptions, condition);
+            this._sound = sound;
+        }
+
+        public _prepare(): void {
+        }
+
+        public execute(): void {
+            if (this._sound !== undefined)
+                this._sound.stop();
+        }
+    }
 } 

+ 56 - 56
src/Actions/babylon.interpolateValueAction.ts

@@ -1,57 +1,57 @@
-module BABYLON {
-    export class InterpolateValueAction extends Action {
-        private _target: any;
-        private _property: string;
-
-        constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, public duration: number = 1000, condition?: Condition, public stopOtherAnimations?: boolean, public onInterpolationDone?: () => void) {
-            super(triggerOptions, condition);
-
-            this._target = target;
-        }
-
-        public _prepare(): void {
-            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
-            this._property = this._getProperty(this.propertyPath);
-        }
-
-        public execute(): void {
-            var scene = this._actionManager.getScene();
-            var keys = [
-                {
-                    frame: 0,
-                    value: this._target[this._property]
-                }, {
-                    frame: 100,
-                    value: this.value
-                }
-            ];
-
-            var dataType: number;
-
-            if (typeof this.value === "number") {
-                dataType = Animation.ANIMATIONTYPE_FLOAT;
-            } else if (this.value instanceof Color3) {
-                dataType = Animation.ANIMATIONTYPE_COLOR3;
-            } else if (this.value instanceof Vector3) {
-                dataType = Animation.ANIMATIONTYPE_VECTOR3;
-            } else if (this.value instanceof Matrix) {
-                dataType = Animation.ANIMATIONTYPE_MATRIX;
-            } else if (this.value instanceof Quaternion) {
-                dataType = Animation.ANIMATIONTYPE_QUATERNION;
-            } else {
-                Tools.Warn("InterpolateValueAction: Unsupported type (" + typeof this.value + ")");
-                return;
-            }
-
-            var animation = new Animation("InterpolateValueAction", this._property, 100 * (1000.0 / this.duration), dataType, Animation.ANIMATIONLOOPMODE_CONSTANT);
-
-            animation.setKeys(keys);
-
-            if (this.stopOtherAnimations) {
-                scene.stopAnimation(this._target);
-            }
-
-            scene.beginDirectAnimation(this._target, [animation], 0, 100, false, 1, this.onInterpolationDone);
-        }
-    }
+module BABYLON {
+    export class InterpolateValueAction extends Action {
+        private _target: any;
+        private _property: string;
+
+        constructor(triggerOptions: any, target: any, public propertyPath: string, public value: any, public duration: number = 1000, condition?: Condition, public stopOtherAnimations?: boolean, public onInterpolationDone?: () => void) {
+            super(triggerOptions, condition);
+
+            this._target = target;
+        }
+
+        public _prepare(): void {
+            this._target = this._getEffectiveTarget(this._target, this.propertyPath);
+            this._property = this._getProperty(this.propertyPath);
+        }
+
+        public execute(): void {
+            var scene = this._actionManager.getScene();
+            var keys = [
+                {
+                    frame: 0,
+                    value: this._target[this._property]
+                }, {
+                    frame: 100,
+                    value: this.value
+                }
+            ];
+
+            var dataType: number;
+
+            if (typeof this.value === "number") {
+                dataType = Animation.ANIMATIONTYPE_FLOAT;
+            } else if (this.value instanceof Color3) {
+                dataType = Animation.ANIMATIONTYPE_COLOR3;
+            } else if (this.value instanceof Vector3) {
+                dataType = Animation.ANIMATIONTYPE_VECTOR3;
+            } else if (this.value instanceof Matrix) {
+                dataType = Animation.ANIMATIONTYPE_MATRIX;
+            } else if (this.value instanceof Quaternion) {
+                dataType = Animation.ANIMATIONTYPE_QUATERNION;
+            } else {
+                Tools.Warn("InterpolateValueAction: Unsupported type (" + typeof this.value + ")");
+                return;
+            }
+
+            var animation = new Animation("InterpolateValueAction", this._property, 100 * (1000.0 / this.duration), dataType, Animation.ANIMATIONLOOPMODE_CONSTANT);
+
+            animation.setKeys(keys);
+
+            if (this.stopOtherAnimations) {
+                scene.stopAnimation(this._target);
+            }
+
+            scene.beginDirectAnimation(this._target, [animation], 0, 100, false, 1, this.onInterpolationDone);
+        }
+    }
 } 

+ 130 - 130
src/Animations/babylon.animatable.ts

@@ -1,131 +1,131 @@
-module BABYLON {
-    export class Animatable {
-        private _localDelayOffset: number;
-        private _pausedDelay: number;
-        private _animations = new Array<Animation>();
-        private _paused = false;
-        private _scene: Scene;
-
-        public animationStarted = false;
-
-        constructor(scene: Scene, public target, public fromFrame: number = 0, public toFrame: number = 100, public loopAnimation: boolean = false, public speedRatio: number = 1.0, public onAnimationEnd?, animations?: any) {
-            if (animations) {
-                this.appendAnimations(target, animations);
-            }
-
-            this._scene = scene;
-            scene._activeAnimatables.push(this);
-        }
-
-        // Methods
-        public getAnimations(): Animation[] {
-            return this._animations;
-        }
-
-        public appendAnimations(target: any, animations: Animation[]): void {
-            for (var index = 0; index < animations.length; index++) {
-                var animation = animations[index];
-
-                animation._target = target;
-                this._animations.push(animation);
-            }
-        }
-
-        public getAnimationByTargetProperty(property: string) {
-            var animations = this._animations;
-
-            for (var index = 0; index < animations.length; index++) {
-                if (animations[index].targetProperty === property) {
-                    return animations[index];
-                }
-            }
-
-            return null;
-        }
-
-        public reset(): void {
-            var animations = this._animations;
-
-            for (var index = 0; index < animations.length; index++) {
-                animations[index].reset();
-            }
-
-            this._localDelayOffset = null;
-            this._pausedDelay = null;
-
-        }
-
-        public goToFrame(frame: number): void {
-            var animations = this._animations;
-
-            for (var index = 0; index < animations.length; index++) {
-                animations[index].goToFrame(frame);
-            }
-        }
-
-        public pause(): void {
-            if (this._paused) {
-                return;
-            }
-            this._paused = true;
-        }
-
-        public restart(): void {
-            this._paused = false;
-        }
-
-        public stop(): void {
-            var index = this._scene._activeAnimatables.indexOf(this);
-
-            if (index > -1) {
-                this._scene._activeAnimatables.splice(index, 1);
-            }
-
-            if (this.onAnimationEnd) {
-                this.onAnimationEnd();
-            }
-        }
-
-        public _animate(delay: number): boolean {
-            if (this._paused) {
-                this.animationStarted = false;
-                if (!this._pausedDelay) {
-                    this._pausedDelay = delay;
-                }
-                return true;
-            }
-
-            if (!this._localDelayOffset) {
-                this._localDelayOffset = delay;
-            } else if (this._pausedDelay) {
-                this._localDelayOffset += delay - this._pausedDelay;
-                this._pausedDelay = null;
-            }
-
-            // Animating
-            var running = false;
-            var animations = this._animations;
-            var index: number;
-
-            for (index = 0; index < animations.length; index++) {
-                var animation = animations[index];
-                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this.speedRatio);
-                running = running || isRunning;
-            }
-
-            this.animationStarted = running;
-
-            if (!running) {
-                // Remove from active animatables
-                index = this._scene._activeAnimatables.indexOf(this);
-                this._scene._activeAnimatables.splice(index, 1);
-            }
-
-            if (!running && this.onAnimationEnd) {
-                this.onAnimationEnd();
-            }
-
-            return running;
-        }
-    }
+module BABYLON {
+    export class Animatable {
+        private _localDelayOffset: number;
+        private _pausedDelay: number;
+        private _animations = new Array<Animation>();
+        private _paused = false;
+        private _scene: Scene;
+
+        public animationStarted = false;
+
+        constructor(scene: Scene, public target, public fromFrame: number = 0, public toFrame: number = 100, public loopAnimation: boolean = false, public speedRatio: number = 1.0, public onAnimationEnd?, animations?: any) {
+            if (animations) {
+                this.appendAnimations(target, animations);
+            }
+
+            this._scene = scene;
+            scene._activeAnimatables.push(this);
+        }
+
+        // Methods
+        public getAnimations(): Animation[] {
+            return this._animations;
+        }
+
+        public appendAnimations(target: any, animations: Animation[]): void {
+            for (var index = 0; index < animations.length; index++) {
+                var animation = animations[index];
+
+                animation._target = target;
+                this._animations.push(animation);
+            }
+        }
+
+        public getAnimationByTargetProperty(property: string) {
+            var animations = this._animations;
+
+            for (var index = 0; index < animations.length; index++) {
+                if (animations[index].targetProperty === property) {
+                    return animations[index];
+                }
+            }
+
+            return null;
+        }
+
+        public reset(): void {
+            var animations = this._animations;
+
+            for (var index = 0; index < animations.length; index++) {
+                animations[index].reset();
+            }
+
+            this._localDelayOffset = null;
+            this._pausedDelay = null;
+
+        }
+
+        public goToFrame(frame: number): void {
+            var animations = this._animations;
+
+            for (var index = 0; index < animations.length; index++) {
+                animations[index].goToFrame(frame);
+            }
+        }
+
+        public pause(): void {
+            if (this._paused) {
+                return;
+            }
+            this._paused = true;
+        }
+
+        public restart(): void {
+            this._paused = false;
+        }
+
+        public stop(): void {
+            var index = this._scene._activeAnimatables.indexOf(this);
+
+            if (index > -1) {
+                this._scene._activeAnimatables.splice(index, 1);
+            }
+
+            if (this.onAnimationEnd) {
+                this.onAnimationEnd();
+            }
+        }
+
+        public _animate(delay: number): boolean {
+            if (this._paused) {
+                this.animationStarted = false;
+                if (!this._pausedDelay) {
+                    this._pausedDelay = delay;
+                }
+                return true;
+            }
+
+            if (!this._localDelayOffset) {
+                this._localDelayOffset = delay;
+            } else if (this._pausedDelay) {
+                this._localDelayOffset += delay - this._pausedDelay;
+                this._pausedDelay = null;
+            }
+
+            // Animating
+            var running = false;
+            var animations = this._animations;
+            var index: number;
+
+            for (index = 0; index < animations.length; index++) {
+                var animation = animations[index];
+                var isRunning = animation.animate(delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this.speedRatio);
+                running = running || isRunning;
+            }
+
+            this.animationStarted = running;
+
+            if (!running) {
+                // Remove from active animatables
+                index = this._scene._activeAnimatables.indexOf(this);
+                this._scene._activeAnimatables.splice(index, 1);
+            }
+
+            if (!running && this.onAnimationEnd) {
+                this.onAnimationEnd();
+            }
+
+            return running;
+        }
+    }
 } 

+ 67 - 0
src/Animations/babylon.animation.js

@@ -403,6 +403,34 @@ var BABYLON;
             }
             return returnValue;
         };
+        Animation.prototype.serialize = function () {
+            var serializationObject = {};
+            serializationObject.name = this.name;
+            serializationObject.property = this.targetProperty;
+            serializationObject.framePerSecond = this.framePerSecond;
+            serializationObject.dataType = this.dataType;
+            serializationObject.loopBehavior = this.loopMode;
+            var dataType = this.dataType;
+            serializationObject.keys = [];
+            var keys = this.getKeys();
+            for (var index = 0; index < keys.length; index++) {
+                var animationKey = keys[index];
+                var key = {};
+                key.frame = animationKey.frame;
+                switch (dataType) {
+                    case Animation.ANIMATIONTYPE_FLOAT:
+                        key.values = [animationKey.value];
+                        break;
+                    case Animation.ANIMATIONTYPE_QUATERNION:
+                    case Animation.ANIMATIONTYPE_MATRIX:
+                    case Animation.ANIMATIONTYPE_VECTOR3:
+                        key.values = animationKey.value.asArray();
+                        break;
+                }
+                serializationObject.keys.push(key);
+            }
+            return serializationObject;
+        };
         Object.defineProperty(Animation, "ANIMATIONTYPE_FLOAT", {
             get: function () {
                 return Animation._ANIMATIONTYPE_FLOAT;
@@ -466,6 +494,45 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
+        Animation.Parse = function (parsedAnimation) {
+            var animation = new Animation(parsedAnimation.name, parsedAnimation.property, parsedAnimation.framePerSecond, parsedAnimation.dataType, parsedAnimation.loopBehavior);
+            var dataType = parsedAnimation.dataType;
+            var keys = [];
+            for (var index = 0; index < parsedAnimation.keys.length; index++) {
+                var key = parsedAnimation.keys[index];
+                var data;
+                switch (dataType) {
+                    case Animation.ANIMATIONTYPE_FLOAT:
+                        data = key.values[0];
+                        break;
+                    case Animation.ANIMATIONTYPE_QUATERNION:
+                        data = BABYLON.Quaternion.FromArray(key.values);
+                        break;
+                    case Animation.ANIMATIONTYPE_MATRIX:
+                        data = BABYLON.Matrix.FromArray(key.values);
+                        break;
+                    case Animation.ANIMATIONTYPE_VECTOR3:
+                    default:
+                        data = BABYLON.Vector3.FromArray(key.values);
+                        break;
+                }
+                keys.push({
+                    frame: key.frame,
+                    value: data
+                });
+            }
+            animation.setKeys(keys);
+            return animation;
+        };
+        Animation.AppendSerializedAnimations = function (source, destination) {
+            if (source.animations) {
+                destination.animations = [];
+                for (var animationIndex = 0; animationIndex < source.animations.length; animationIndex++) {
+                    var animation = source.animations[animationIndex];
+                    destination.animations.push(animation.serialize());
+                }
+            }
+        };
         // Statics
         Animation._ANIMATIONTYPE_FLOAT = 0;
         Animation._ANIMATIONTYPE_VECTOR3 = 1;

Plik diff jest za duży
+ 601 - 520
src/Animations/babylon.animation.ts


+ 188 - 188
src/Animations/babylon.easing.ts

@@ -1,188 +1,188 @@
-module BABYLON {
-
-    export interface IEasingFunction {
-        ease(gradient: number): number;
-    }
-
-    export class EasingFunction implements IEasingFunction {
-        //Statics
-        private static _EASINGMODE_EASEIN = 0;
-        private static _EASINGMODE_EASEOUT = 1;
-        private static _EASINGMODE_EASEINOUT = 2;
-
-        public static get EASINGMODE_EASEIN(): number {
-            return EasingFunction._EASINGMODE_EASEIN;
-        }
-
-        public static get EASINGMODE_EASEOUT(): number {
-            return EasingFunction._EASINGMODE_EASEOUT;
-        }
-
-        public static get EASINGMODE_EASEINOUT(): number {
-            return EasingFunction._EASINGMODE_EASEINOUT;
-        }
-
-        // Properties
-        private _easingMode = EasingFunction.EASINGMODE_EASEIN;
-
-        public setEasingMode(easingMode: number) {
-            var n = Math.min(Math.max(easingMode, 0), 2);
-            this._easingMode = n;
-        }
-        public getEasingMode(): number {
-            return this._easingMode;
-        }
-
-        public easeInCore(gradient: number): number {
-            throw new Error('You must implement this method');
-        }
-
-        public ease(gradient: number): number {
-            switch (this._easingMode) {
-                case EasingFunction.EASINGMODE_EASEIN:
-                    return this.easeInCore(gradient);
-                case EasingFunction.EASINGMODE_EASEOUT:
-                    return (1 - this.easeInCore(1 - gradient));
-            }
-
-            if (gradient >= 0.5) {
-                return (((1 - this.easeInCore((1 - gradient) * 2)) * 0.5) + 0.5);
-            }
-
-            return (this.easeInCore(gradient * 2) * 0.5);
-        }
-
-    }
-
-    export class CircleEase extends EasingFunction implements IEasingFunction {
-        public easeInCore(gradient: number): number {
-            gradient = Math.max(0, Math.min(1, gradient));
-            return (1.0 - Math.sqrt(1.0 - (gradient * gradient)));
-        }
-    }
-
-    export class BackEase extends EasingFunction implements IEasingFunction {
-        constructor(public amplitude: number = 1) {
-            super();
-        }
-
-        public easeInCore(gradient: number): number {
-            var num = Math.max(0, this.amplitude);
-            return (Math.pow(gradient, 3.0) - ((gradient * num) * Math.sin(3.1415926535897931 * gradient)));
-        }
-    }
-
-    export class BounceEase extends EasingFunction implements IEasingFunction {
-        constructor(public bounces: number= 3, public bounciness: number= 2) {
-            super();
-        }
-
-        public easeInCore(gradient: number): number {
-            var y = Math.max(0.0, this.bounces);
-            var bounciness = this.bounciness;
-            if (bounciness <= 1.0) {
-                bounciness = 1.001;
-            }
-            var num9 = Math.pow(bounciness, y);
-            var num5 = 1.0 - bounciness;
-            var num4 = ((1.0 - num9) / num5) + (num9 * 0.5);
-            var num15 = gradient * num4;
-            var num65 = Math.log((-num15 * (1.0 - bounciness)) + 1.0) / Math.log(bounciness);
-            var num3 = Math.floor(num65);
-            var num13 = num3 + 1.0;
-            var num8 = (1.0 - Math.pow(bounciness, num3)) / (num5 * num4);
-            var num12 = (1.0 - Math.pow(bounciness, num13)) / (num5 * num4);
-            var num7 = (num8 + num12) * 0.5;
-            var num6 = gradient - num7;
-            var num2 = num7 - num8;
-            return (((-Math.pow(1.0 / bounciness, y - num3) / (num2 * num2)) * (num6 - num2)) * (num6 + num2));
-        }
-    }
-
-    export class CubicEase extends EasingFunction implements IEasingFunction {
-        public easeInCore(gradient: number): number {
-            return (gradient * gradient * gradient);
-        }
-    }
-
-    export class ElasticEase extends EasingFunction implements IEasingFunction {
-        constructor(public oscillations: number= 3, public springiness: number= 3) {
-            super();
-        }
-
-        public easeInCore(gradient: number): number {
-            var num2;
-            var num3 = Math.max(0.0, this.oscillations);
-            var num = Math.max(0.0, this.springiness);
-
-            if (num == 0) {
-                num2 = gradient;
-            }else {
-                num2 = (Math.exp(num * gradient) - 1.0) / (Math.exp(num) - 1.0);
-            }
-            return (num2 * Math.sin(((6.2831853071795862 * num3) + 1.5707963267948966) * gradient));
-        }
-    }
-
-    export class ExponentialEase  extends EasingFunction implements IEasingFunction {
-        constructor(public exponent: number= 2) {
-            super();
-        }
-
-        public easeInCore(gradient: number): number {
-            if (this.exponent <= 0) {
-                return gradient;
-            }
-
-            return ((Math.exp(this.exponent * gradient) - 1.0) / (Math.exp(this.exponent) - 1.0));
-        }
-    }
-
-    export class PowerEase  extends EasingFunction implements IEasingFunction {
-        constructor(public power: number= 2) {
-            super();
-        }
-
-        public easeInCore(gradient: number): number {
-            var y = Math.max(0.0, this.power);
-            return Math.pow(gradient, y);
-        }
-    }
-
-    export class QuadraticEase extends EasingFunction implements IEasingFunction {
-        public easeInCore(gradient: number): number {
-            return (gradient * gradient);
-
-           
-
-        }
-    }
-
-    export class QuarticEase extends EasingFunction implements IEasingFunction {
-        public easeInCore(gradient: number): number {
-            return (gradient * gradient * gradient * gradient);
-        }
-    }
-
-    export class QuinticEase extends EasingFunction implements IEasingFunction {
-        public easeInCore(gradient: number): number {
-            return (gradient * gradient * gradient * gradient * gradient);
-        }
-    }
-
-    export class SineEase  extends EasingFunction implements IEasingFunction {
-        public easeInCore(gradient: number): number {
-            return (1.0 - Math.sin(1.5707963267948966 * (1.0 - gradient)));
-        }
-    }
-
-    export class BezierCurveEase extends EasingFunction implements IEasingFunction {
-        constructor(public x1: number= 0, public y1: number= 0, public x2: number= 1, public y2: number= 1) {
-            super();
-        }
-
-        public easeInCore(gradient: number): number {
-            return BezierCurve.interpolate(gradient, this.x1, this.y1, this.x2, this.y2);
-        }
-    }
-}
+module BABYLON {
+
+    export interface IEasingFunction {
+        ease(gradient: number): number;
+    }
+
+    export class EasingFunction implements IEasingFunction {
+        //Statics
+        private static _EASINGMODE_EASEIN = 0;
+        private static _EASINGMODE_EASEOUT = 1;
+        private static _EASINGMODE_EASEINOUT = 2;
+
+        public static get EASINGMODE_EASEIN(): number {
+            return EasingFunction._EASINGMODE_EASEIN;
+        }
+
+        public static get EASINGMODE_EASEOUT(): number {
+            return EasingFunction._EASINGMODE_EASEOUT;
+        }
+
+        public static get EASINGMODE_EASEINOUT(): number {
+            return EasingFunction._EASINGMODE_EASEINOUT;
+        }
+
+        // Properties
+        private _easingMode = EasingFunction.EASINGMODE_EASEIN;
+
+        public setEasingMode(easingMode: number) {
+            var n = Math.min(Math.max(easingMode, 0), 2);
+            this._easingMode = n;
+        }
+        public getEasingMode(): number {
+            return this._easingMode;
+        }
+
+        public easeInCore(gradient: number): number {
+            throw new Error('You must implement this method');
+        }
+
+        public ease(gradient: number): number {
+            switch (this._easingMode) {
+                case EasingFunction.EASINGMODE_EASEIN:
+                    return this.easeInCore(gradient);
+                case EasingFunction.EASINGMODE_EASEOUT:
+                    return (1 - this.easeInCore(1 - gradient));
+            }
+
+            if (gradient >= 0.5) {
+                return (((1 - this.easeInCore((1 - gradient) * 2)) * 0.5) + 0.5);
+            }
+
+            return (this.easeInCore(gradient * 2) * 0.5);
+        }
+
+    }
+
+    export class CircleEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            gradient = Math.max(0, Math.min(1, gradient));
+            return (1.0 - Math.sqrt(1.0 - (gradient * gradient)));
+        }
+    }
+
+    export class BackEase extends EasingFunction implements IEasingFunction {
+        constructor(public amplitude: number = 1) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            var num = Math.max(0, this.amplitude);
+            return (Math.pow(gradient, 3.0) - ((gradient * num) * Math.sin(3.1415926535897931 * gradient)));
+        }
+    }
+
+    export class BounceEase extends EasingFunction implements IEasingFunction {
+        constructor(public bounces: number= 3, public bounciness: number= 2) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            var y = Math.max(0.0, this.bounces);
+            var bounciness = this.bounciness;
+            if (bounciness <= 1.0) {
+                bounciness = 1.001;
+            }
+            var num9 = Math.pow(bounciness, y);
+            var num5 = 1.0 - bounciness;
+            var num4 = ((1.0 - num9) / num5) + (num9 * 0.5);
+            var num15 = gradient * num4;
+            var num65 = Math.log((-num15 * (1.0 - bounciness)) + 1.0) / Math.log(bounciness);
+            var num3 = Math.floor(num65);
+            var num13 = num3 + 1.0;
+            var num8 = (1.0 - Math.pow(bounciness, num3)) / (num5 * num4);
+            var num12 = (1.0 - Math.pow(bounciness, num13)) / (num5 * num4);
+            var num7 = (num8 + num12) * 0.5;
+            var num6 = gradient - num7;
+            var num2 = num7 - num8;
+            return (((-Math.pow(1.0 / bounciness, y - num3) / (num2 * num2)) * (num6 - num2)) * (num6 + num2));
+        }
+    }
+
+    export class CubicEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (gradient * gradient * gradient);
+        }
+    }
+
+    export class ElasticEase extends EasingFunction implements IEasingFunction {
+        constructor(public oscillations: number= 3, public springiness: number= 3) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            var num2;
+            var num3 = Math.max(0.0, this.oscillations);
+            var num = Math.max(0.0, this.springiness);
+
+            if (num == 0) {
+                num2 = gradient;
+            }else {
+                num2 = (Math.exp(num * gradient) - 1.0) / (Math.exp(num) - 1.0);
+            }
+            return (num2 * Math.sin(((6.2831853071795862 * num3) + 1.5707963267948966) * gradient));
+        }
+    }
+
+    export class ExponentialEase  extends EasingFunction implements IEasingFunction {
+        constructor(public exponent: number= 2) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            if (this.exponent <= 0) {
+                return gradient;
+            }
+
+            return ((Math.exp(this.exponent * gradient) - 1.0) / (Math.exp(this.exponent) - 1.0));
+        }
+    }
+
+    export class PowerEase  extends EasingFunction implements IEasingFunction {
+        constructor(public power: number= 2) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            var y = Math.max(0.0, this.power);
+            return Math.pow(gradient, y);
+        }
+    }
+
+    export class QuadraticEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (gradient * gradient);
+
+           
+
+        }
+    }
+
+    export class QuarticEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (gradient * gradient * gradient * gradient);
+        }
+    }
+
+    export class QuinticEase extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (gradient * gradient * gradient * gradient * gradient);
+        }
+    }
+
+    export class SineEase  extends EasingFunction implements IEasingFunction {
+        public easeInCore(gradient: number): number {
+            return (1.0 - Math.sin(1.5707963267948966 * (1.0 - gradient)));
+        }
+    }
+
+    export class BezierCurveEase extends EasingFunction implements IEasingFunction {
+        constructor(public x1: number= 0, public y1: number= 0, public x2: number= 1, public y2: number= 1) {
+            super();
+        }
+
+        public easeInCore(gradient: number): number {
+            return BezierCurve.interpolate(gradient, this.x1, this.y1, this.x2, this.y2);
+        }
+    }
+}

+ 127 - 127
src/Audio/babylon.analyser.ts

@@ -1,128 +1,128 @@
-module BABYLON {
-    export class Analyser {
-        public SMOOTHING = 0.75;
-        public FFT_SIZE = 512;
-        public BARGRAPHAMPLITUDE = 256;
-        public DEBUGCANVASPOS = { x: 20, y: 20 };
-        public DEBUGCANVASSIZE = { width: 320, height: 200 }
-
-        private _byteFreqs: Uint8Array;
-        private _byteTime: Uint8Array;
-        private _floatFreqs: Float32Array;
-        private _webAudioAnalyser: AnalyserNode;
-        private _debugCanvas: HTMLCanvasElement;
-        private _debugCanvasContext: CanvasRenderingContext2D;
-        private _scene: Scene;
-        private _registerFunc;
-        private _audioEngine: AudioEngine;
-
-        constructor(scene: Scene) {
-            this._scene = scene;
-            this._audioEngine = Engine.audioEngine;
-            if (this._audioEngine.canUseWebAudio) {
-                this._webAudioAnalyser = this._audioEngine.audioContext.createAnalyser();
-                this._webAudioAnalyser.minDecibels = -140;
-                this._webAudioAnalyser.maxDecibels = 0;
-                this._byteFreqs = new Uint8Array(this._webAudioAnalyser.frequencyBinCount);
-                this._byteTime = new Uint8Array(this._webAudioAnalyser.frequencyBinCount);
-                this._floatFreqs = new Float32Array(this._webAudioAnalyser.frequencyBinCount);
-            }
-        }
-
-        public getFrequencyBinCount(): number {
-            if (this._audioEngine.canUseWebAudio) {
-                return this._webAudioAnalyser.frequencyBinCount;
-            }
-            else {
-                return 0;
-            }
-        }
-
-        public getByteFrequencyData(): Uint8Array {
-            if (this._audioEngine.canUseWebAudio) {
-                this._webAudioAnalyser.smoothingTimeConstant = this.SMOOTHING;
-                this._webAudioAnalyser.fftSize = this.FFT_SIZE;
-                this._webAudioAnalyser.getByteFrequencyData(this._byteFreqs);
-            }
-            return this._byteFreqs;
-        }
-
-        public getByteTimeDomainData(): Uint8Array {
-            if (this._audioEngine.canUseWebAudio) {
-                this._webAudioAnalyser.smoothingTimeConstant = this.SMOOTHING;
-                this._webAudioAnalyser.fftSize = this.FFT_SIZE;
-                this._webAudioAnalyser.getByteTimeDomainData(this._byteTime);
-            }
-            return this._byteTime;
-        }
-
-        public getFloatFrequencyData(): Uint8Array {
-            if (this._audioEngine.canUseWebAudio) {
-                this._webAudioAnalyser.smoothingTimeConstant = this.SMOOTHING;
-                this._webAudioAnalyser.fftSize = this.FFT_SIZE;
-                this._webAudioAnalyser.getFloatFrequencyData(this._floatFreqs);
-            }
-            return this._floatFreqs;
-        }
-
-        public drawDebugCanvas() {
-            if (this._audioEngine.canUseWebAudio) {
-                if (!this._debugCanvas) {
-                    this._debugCanvas = document.createElement("canvas");
-                    this._debugCanvas.width = this.DEBUGCANVASSIZE.width;
-                    this._debugCanvas.height = this.DEBUGCANVASSIZE.height;
-                    this._debugCanvas.style.position = "absolute";
-                    this._debugCanvas.style.top = this.DEBUGCANVASPOS.y + "px" ;
-                    this._debugCanvas.style.left = this.DEBUGCANVASPOS.x + "px" ;
-                    this._debugCanvasContext = this._debugCanvas.getContext("2d");
-                    document.body.appendChild(this._debugCanvas);
-                    this._registerFunc = () => {
-                        this.drawDebugCanvas();
-                    };
-                    this._scene.registerBeforeRender(this._registerFunc);
-                }
-                if (this._registerFunc) {
-                    var workingArray = this.getByteFrequencyData();
-
-                    this._debugCanvasContext.fillStyle = 'rgb(0, 0, 0)';
-                    this._debugCanvasContext.fillRect(0, 0, this.DEBUGCANVASSIZE.width, this.DEBUGCANVASSIZE.height);
-
-                    // Draw the frequency domain chart.
-                    for (var i = 0; i < this.getFrequencyBinCount(); i++) {
-                        var value = workingArray[i];
-                        var percent = value / this.BARGRAPHAMPLITUDE;
-                        var height = this.DEBUGCANVASSIZE.height * percent;
-                        var offset = this.DEBUGCANVASSIZE.height - height - 1;
-                        var barWidth = this.DEBUGCANVASSIZE.width / this.getFrequencyBinCount();
-                        var hue = i / this.getFrequencyBinCount() * 360;
-                        this._debugCanvasContext.fillStyle = 'hsl(' + hue + ', 100%, 50%)';
-                        this._debugCanvasContext.fillRect(i * barWidth, offset, barWidth, height);
-                    }
-                }
-            }
-        }
-
-        public stopDebugCanvas() {
-            if (this._debugCanvas) {
-                this._scene.unregisterBeforeRender(this._registerFunc);
-                this._registerFunc = null;
-                document.body.removeChild(this._debugCanvas);
-                this._debugCanvas = null;
-                this._debugCanvasContext = null;
-            }
-        }
-
-        public connectAudioNodes(inputAudioNode: AudioNode, outputAudioNode: AudioNode) {
-            if (this._audioEngine.canUseWebAudio) {
-                inputAudioNode.connect(this._webAudioAnalyser);
-                this._webAudioAnalyser.connect(outputAudioNode);
-            }
-        }
-
-        public dispose() {
-            if (this._audioEngine.canUseWebAudio) {
-                this._webAudioAnalyser.disconnect();
-            }
-        }
-    }
+module BABYLON {
+    export class Analyser {
+        public SMOOTHING = 0.75;
+        public FFT_SIZE = 512;
+        public BARGRAPHAMPLITUDE = 256;
+        public DEBUGCANVASPOS = { x: 20, y: 20 };
+        public DEBUGCANVASSIZE = { width: 320, height: 200 }
+
+        private _byteFreqs: Uint8Array;
+        private _byteTime: Uint8Array;
+        private _floatFreqs: Float32Array;
+        private _webAudioAnalyser: AnalyserNode;
+        private _debugCanvas: HTMLCanvasElement;
+        private _debugCanvasContext: CanvasRenderingContext2D;
+        private _scene: Scene;
+        private _registerFunc;
+        private _audioEngine: AudioEngine;
+
+        constructor(scene: Scene) {
+            this._scene = scene;
+            this._audioEngine = Engine.audioEngine;
+            if (this._audioEngine.canUseWebAudio) {
+                this._webAudioAnalyser = this._audioEngine.audioContext.createAnalyser();
+                this._webAudioAnalyser.minDecibels = -140;
+                this._webAudioAnalyser.maxDecibels = 0;
+                this._byteFreqs = new Uint8Array(this._webAudioAnalyser.frequencyBinCount);
+                this._byteTime = new Uint8Array(this._webAudioAnalyser.frequencyBinCount);
+                this._floatFreqs = new Float32Array(this._webAudioAnalyser.frequencyBinCount);
+            }
+        }
+
+        public getFrequencyBinCount(): number {
+            if (this._audioEngine.canUseWebAudio) {
+                return this._webAudioAnalyser.frequencyBinCount;
+            }
+            else {
+                return 0;
+            }
+        }
+
+        public getByteFrequencyData(): Uint8Array {
+            if (this._audioEngine.canUseWebAudio) {
+                this._webAudioAnalyser.smoothingTimeConstant = this.SMOOTHING;
+                this._webAudioAnalyser.fftSize = this.FFT_SIZE;
+                this._webAudioAnalyser.getByteFrequencyData(this._byteFreqs);
+            }
+            return this._byteFreqs;
+        }
+
+        public getByteTimeDomainData(): Uint8Array {
+            if (this._audioEngine.canUseWebAudio) {
+                this._webAudioAnalyser.smoothingTimeConstant = this.SMOOTHING;
+                this._webAudioAnalyser.fftSize = this.FFT_SIZE;
+                this._webAudioAnalyser.getByteTimeDomainData(this._byteTime);
+            }
+            return this._byteTime;
+        }
+
+        public getFloatFrequencyData(): Uint8Array {
+            if (this._audioEngine.canUseWebAudio) {
+                this._webAudioAnalyser.smoothingTimeConstant = this.SMOOTHING;
+                this._webAudioAnalyser.fftSize = this.FFT_SIZE;
+                this._webAudioAnalyser.getFloatFrequencyData(this._floatFreqs);
+            }
+            return this._floatFreqs;
+        }
+
+        public drawDebugCanvas() {
+            if (this._audioEngine.canUseWebAudio) {
+                if (!this._debugCanvas) {
+                    this._debugCanvas = document.createElement("canvas");
+                    this._debugCanvas.width = this.DEBUGCANVASSIZE.width;
+                    this._debugCanvas.height = this.DEBUGCANVASSIZE.height;
+                    this._debugCanvas.style.position = "absolute";
+                    this._debugCanvas.style.top = this.DEBUGCANVASPOS.y + "px" ;
+                    this._debugCanvas.style.left = this.DEBUGCANVASPOS.x + "px" ;
+                    this._debugCanvasContext = this._debugCanvas.getContext("2d");
+                    document.body.appendChild(this._debugCanvas);
+                    this._registerFunc = () => {
+                        this.drawDebugCanvas();
+                    };
+                    this._scene.registerBeforeRender(this._registerFunc);
+                }
+                if (this._registerFunc) {
+                    var workingArray = this.getByteFrequencyData();
+
+                    this._debugCanvasContext.fillStyle = 'rgb(0, 0, 0)';
+                    this._debugCanvasContext.fillRect(0, 0, this.DEBUGCANVASSIZE.width, this.DEBUGCANVASSIZE.height);
+
+                    // Draw the frequency domain chart.
+                    for (var i = 0; i < this.getFrequencyBinCount(); i++) {
+                        var value = workingArray[i];
+                        var percent = value / this.BARGRAPHAMPLITUDE;
+                        var height = this.DEBUGCANVASSIZE.height * percent;
+                        var offset = this.DEBUGCANVASSIZE.height - height - 1;
+                        var barWidth = this.DEBUGCANVASSIZE.width / this.getFrequencyBinCount();
+                        var hue = i / this.getFrequencyBinCount() * 360;
+                        this._debugCanvasContext.fillStyle = 'hsl(' + hue + ', 100%, 50%)';
+                        this._debugCanvasContext.fillRect(i * barWidth, offset, barWidth, height);
+                    }
+                }
+            }
+        }
+
+        public stopDebugCanvas() {
+            if (this._debugCanvas) {
+                this._scene.unregisterBeforeRender(this._registerFunc);
+                this._registerFunc = null;
+                document.body.removeChild(this._debugCanvas);
+                this._debugCanvas = null;
+                this._debugCanvasContext = null;
+            }
+        }
+
+        public connectAudioNodes(inputAudioNode: AudioNode, outputAudioNode: AudioNode) {
+            if (this._audioEngine.canUseWebAudio) {
+                inputAudioNode.connect(this._webAudioAnalyser);
+                this._webAudioAnalyser.connect(outputAudioNode);
+            }
+        }
+
+        public dispose() {
+            if (this._audioEngine.canUseWebAudio) {
+                this._webAudioAnalyser.disconnect();
+            }
+        }
+    }
 }

+ 84 - 84
src/Audio/babylon.audioEngine.ts

@@ -1,84 +1,84 @@
-module BABYLON {
-    export class AudioEngine {
-        private _audioContext: AudioContext = null;
-        private _audioContextInitialized = false;
-        public canUseWebAudio: boolean = false;
-        public masterGain: GainNode;
-
-        private _connectedAnalyser: Analyser;
-        public WarnedWebAudioUnsupported: boolean = false;
-
-        public get audioContext(): AudioContext {
-            if (!this._audioContextInitialized) {
-                this._initializeAudioContext();
-            }
-            return this._audioContext;
-        }
-
-        constructor() {
-            if (typeof window.AudioContext !== 'undefined' || typeof window.webkitAudioContext !== 'undefined') {
-                window.AudioContext = window.AudioContext || window.webkitAudioContext;
-                this.canUseWebAudio = true;
-            }
-        }
-
-        private _initializeAudioContext() {
-            try {
-                if (this.canUseWebAudio) {
-                    this._audioContext = new AudioContext();
-                    // create a global volume gain node 
-                    this.masterGain = this._audioContext.createGain();
-                    this.masterGain.gain.value = 1;
-                    this.masterGain.connect(this._audioContext.destination);
-                    this._audioContextInitialized = true;
-                }
-            }
-            catch (e) {
-                this.canUseWebAudio = false;
-                Tools.Error("Web Audio: " + e.message);
-            }
-        }
-
-        public dispose() {
-            if (this.canUseWebAudio && this._audioContextInitialized) {
-                if (this._connectedAnalyser) {
-                    this._connectedAnalyser.stopDebugCanvas();
-                    this._connectedAnalyser.dispose();
-                    this.masterGain.disconnect();
-                    this.masterGain.connect(this._audioContext.destination);
-                    this._connectedAnalyser = null;
-                }
-                this.masterGain.gain.value = 1;
-            }
-            this.WarnedWebAudioUnsupported = false;
-        }
-
-        public getGlobalVolume(): number {
-            if (this.canUseWebAudio && this._audioContextInitialized) {
-                return this.masterGain.gain.value;
-            }
-            else {
-                return -1;
-            }
-        }
-
-        public setGlobalVolume(newVolume: number) {
-            if (this.canUseWebAudio && this._audioContextInitialized) {
-                this.masterGain.gain.value = newVolume;
-            }
-        }
-
-        public connectToAnalyser(analyser: Analyser) {
-            if (this._connectedAnalyser) {
-                this._connectedAnalyser.stopDebugCanvas();
-            }
-            if (this.canUseWebAudio && this._audioContextInitialized) {
-                this._connectedAnalyser = analyser;
-                this.masterGain.disconnect();
-                this._connectedAnalyser.connectAudioNodes(this.masterGain, this._audioContext.destination);
-            }
-        }
-    }
-}
-
-
+module BABYLON {
+    export class AudioEngine {
+        private _audioContext: AudioContext = null;
+        private _audioContextInitialized = false;
+        public canUseWebAudio: boolean = false;
+        public masterGain: GainNode;
+
+        private _connectedAnalyser: Analyser;
+        public WarnedWebAudioUnsupported: boolean = false;
+
+        public get audioContext(): AudioContext {
+            if (!this._audioContextInitialized) {
+                this._initializeAudioContext();
+            }
+            return this._audioContext;
+        }
+
+        constructor() {
+            if (typeof window.AudioContext !== 'undefined' || typeof window.webkitAudioContext !== 'undefined') {
+                window.AudioContext = window.AudioContext || window.webkitAudioContext;
+                this.canUseWebAudio = true;
+            }
+        }
+
+        private _initializeAudioContext() {
+            try {
+                if (this.canUseWebAudio) {
+                    this._audioContext = new AudioContext();
+                    // create a global volume gain node 
+                    this.masterGain = this._audioContext.createGain();
+                    this.masterGain.gain.value = 1;
+                    this.masterGain.connect(this._audioContext.destination);
+                    this._audioContextInitialized = true;
+                }
+            }
+            catch (e) {
+                this.canUseWebAudio = false;
+                Tools.Error("Web Audio: " + e.message);
+            }
+        }
+
+        public dispose() {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
+                if (this._connectedAnalyser) {
+                    this._connectedAnalyser.stopDebugCanvas();
+                    this._connectedAnalyser.dispose();
+                    this.masterGain.disconnect();
+                    this.masterGain.connect(this._audioContext.destination);
+                    this._connectedAnalyser = null;
+                }
+                this.masterGain.gain.value = 1;
+            }
+            this.WarnedWebAudioUnsupported = false;
+        }
+
+        public getGlobalVolume(): number {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
+                return this.masterGain.gain.value;
+            }
+            else {
+                return -1;
+            }
+        }
+
+        public setGlobalVolume(newVolume: number) {
+            if (this.canUseWebAudio && this._audioContextInitialized) {
+                this.masterGain.gain.value = newVolume;
+            }
+        }
+
+        public connectToAnalyser(analyser: Analyser) {
+            if (this._connectedAnalyser) {
+                this._connectedAnalyser.stopDebugCanvas();
+            }
+            if (this.canUseWebAudio && this._audioContextInitialized) {
+                this._connectedAnalyser = analyser;
+                this.masterGain.disconnect();
+                this._connectedAnalyser.connectAudioNodes(this.masterGain, this._audioContext.destination);
+            }
+        }
+    }
+}
+
+

+ 32 - 0
src/Audio/babylon.sound.js

@@ -439,6 +439,38 @@ var BABYLON;
                 this._updateDirection();
             }
         };
+        Sound.Parse = function (parsedSound, scene, rootUrl) {
+            var soundName = parsedSound.name;
+            var soundUrl = rootUrl + soundName;
+            var options = {
+                autoplay: parsedSound.autoplay, loop: parsedSound.loop, volume: parsedSound.volume,
+                spatialSound: parsedSound.spatialSound, maxDistance: parsedSound.maxDistance,
+                rolloffFactor: parsedSound.rolloffFactor,
+                refDistance: parsedSound.refDistance,
+                distanceModel: parsedSound.distanceModel,
+                playbackRate: parsedSound.playbackRate
+            };
+            var newSound = new Sound(soundName, soundUrl, scene, function () { scene._removePendingData(newSound); }, options);
+            scene._addPendingData(newSound);
+            if (parsedSound.position) {
+                var soundPosition = BABYLON.Vector3.FromArray(parsedSound.position);
+                newSound.setPosition(soundPosition);
+            }
+            if (parsedSound.isDirectional) {
+                newSound.setDirectionalCone(parsedSound.coneInnerAngle || 360, parsedSound.coneOuterAngle || 360, parsedSound.coneOuterGain || 0);
+                if (parsedSound.localDirectionToMesh) {
+                    var localDirectionToMesh = BABYLON.Vector3.FromArray(parsedSound.localDirectionToMesh);
+                    newSound.setLocalDirectionToMesh(localDirectionToMesh);
+                }
+            }
+            if (parsedSound.connectedMeshId) {
+                var connectedMesh = scene.getMeshByID(parsedSound.connectedMeshId);
+                if (connectedMesh) {
+                    newSound.attachToMesh(connectedMesh);
+                }
+            }
+            return newSound;
+        };
         return Sound;
     })();
     BABYLON.Sound = Sound;

Plik diff jest za duży
+ 518 - 481
src/Audio/babylon.sound.ts


+ 113 - 113
src/Audio/babylon.soundtrack.ts

@@ -1,114 +1,114 @@
-module BABYLON {
-    export class SoundTrack {
-        private _outputAudioNode: GainNode;
-        private _inputAudioNode: AudioNode;
-        private _trackConvolver: ConvolverNode;
-        private _scene: Scene;
-        public id: number = -1;
-        public soundCollection: Array<Sound>;
-        private _isMainTrack: boolean = false;
-        private _connectedAnalyser: Analyser;
-        private _options;
-        private _isInitialized = false;
-
-        constructor(scene: Scene, options?: any) {
-            this._scene = scene;
-            this.soundCollection = new Array();
-            this._options = options;
-
-            if (!this._isMainTrack) {
-                this._scene.soundTracks.push(this);
-                this.id = this._scene.soundTracks.length - 1;
-            }
-        }
-
-        private _initializeSoundTrackAudioGraph() {
-            if (Engine.audioEngine.canUseWebAudio) {
-                this._outputAudioNode = Engine.audioEngine.audioContext.createGain();
-                this._outputAudioNode.connect(Engine.audioEngine.masterGain);
-
-                if (this._options) {
-                    if (this._options.volume) { this._outputAudioNode.gain.value = this._options.volume; }
-                    if (this._options.mainTrack) { this._isMainTrack = this._options.mainTrack; }
-                }
-
-                this._isInitialized = true;
-            }
-        }
-
-        public dispose() {
-            if (Engine.audioEngine.canUseWebAudio) {
-                if (this._connectedAnalyser) {
-                    this._connectedAnalyser.stopDebugCanvas();
-                }
-                while (this.soundCollection.length) {
-                    this.soundCollection[0].dispose();
-                }
-                if (this._outputAudioNode) {
-                    this._outputAudioNode.disconnect();
-                }
-                this._outputAudioNode = null;
-            }
-        }
-
-        public AddSound(sound: Sound) {
-            if (!this._isInitialized) {
-                this._initializeSoundTrackAudioGraph();
-            }
-            if (Engine.audioEngine.canUseWebAudio) {
-                sound.connectToSoundTrackAudioNode(this._outputAudioNode);
-            }
-            if (sound.soundTrackId) {
-                if (sound.soundTrackId === -1) {
-                    this._scene.mainSoundTrack.RemoveSound(sound);
-                }
-                else {
-                    this._scene.soundTracks[sound.soundTrackId].RemoveSound(sound);
-                }
-            }
-
-            this.soundCollection.push(sound);
-            sound.soundTrackId = this.id;
-        }
-
-        public RemoveSound(sound: Sound) {
-            var index = this.soundCollection.indexOf(sound);
-            if (index !== -1) {
-                this.soundCollection.splice(index, 1);
-            }
-        }
-
-        public setVolume(newVolume: number) {
-            if (Engine.audioEngine.canUseWebAudio) {
-                this._outputAudioNode.gain.value = newVolume;
-            }
-        }
-
-        public switchPanningModelToHRTF() {
-            if (Engine.audioEngine.canUseWebAudio) {
-                for (var i = 0; i < this.soundCollection.length; i++) {
-                    this.soundCollection[i].switchPanningModelToHRTF();
-                }
-            }
-        }
-
-        public switchPanningModelToEqualPower() {
-            if (Engine.audioEngine.canUseWebAudio) {
-                for (var i = 0; i < this.soundCollection.length; i++) {
-                    this.soundCollection[i].switchPanningModelToEqualPower();
-                }
-            }
-        }
-
-        public connectToAnalyser(analyser: Analyser) {
-            if (this._connectedAnalyser) {
-                this._connectedAnalyser.stopDebugCanvas();
-            }
-            this._connectedAnalyser = analyser;
-            if (Engine.audioEngine.canUseWebAudio) {
-                this._outputAudioNode.disconnect();
-                this._connectedAnalyser.connectAudioNodes(this._outputAudioNode, Engine.audioEngine.masterGain);
-            }
-        }
-    }
+module BABYLON {
+    export class SoundTrack {
+        private _outputAudioNode: GainNode;
+        private _inputAudioNode: AudioNode;
+        private _trackConvolver: ConvolverNode;
+        private _scene: Scene;
+        public id: number = -1;
+        public soundCollection: Array<Sound>;
+        private _isMainTrack: boolean = false;
+        private _connectedAnalyser: Analyser;
+        private _options;
+        private _isInitialized = false;
+
+        constructor(scene: Scene, options?: any) {
+            this._scene = scene;
+            this.soundCollection = new Array();
+            this._options = options;
+
+            if (!this._isMainTrack) {
+                this._scene.soundTracks.push(this);
+                this.id = this._scene.soundTracks.length - 1;
+            }
+        }
+
+        private _initializeSoundTrackAudioGraph() {
+            if (Engine.audioEngine.canUseWebAudio) {
+                this._outputAudioNode = Engine.audioEngine.audioContext.createGain();
+                this._outputAudioNode.connect(Engine.audioEngine.masterGain);
+
+                if (this._options) {
+                    if (this._options.volume) { this._outputAudioNode.gain.value = this._options.volume; }
+                    if (this._options.mainTrack) { this._isMainTrack = this._options.mainTrack; }
+                }
+
+                this._isInitialized = true;
+            }
+        }
+
+        public dispose() {
+            if (Engine.audioEngine.canUseWebAudio) {
+                if (this._connectedAnalyser) {
+                    this._connectedAnalyser.stopDebugCanvas();
+                }
+                while (this.soundCollection.length) {
+                    this.soundCollection[0].dispose();
+                }
+                if (this._outputAudioNode) {
+                    this._outputAudioNode.disconnect();
+                }
+                this._outputAudioNode = null;
+            }
+        }
+
+        public AddSound(sound: Sound) {
+            if (!this._isInitialized) {
+                this._initializeSoundTrackAudioGraph();
+            }
+            if (Engine.audioEngine.canUseWebAudio) {
+                sound.connectToSoundTrackAudioNode(this._outputAudioNode);
+            }
+            if (sound.soundTrackId) {
+                if (sound.soundTrackId === -1) {
+                    this._scene.mainSoundTrack.RemoveSound(sound);
+                }
+                else {
+                    this._scene.soundTracks[sound.soundTrackId].RemoveSound(sound);
+                }
+            }
+
+            this.soundCollection.push(sound);
+            sound.soundTrackId = this.id;
+        }
+
+        public RemoveSound(sound: Sound) {
+            var index = this.soundCollection.indexOf(sound);
+            if (index !== -1) {
+                this.soundCollection.splice(index, 1);
+            }
+        }
+
+        public setVolume(newVolume: number) {
+            if (Engine.audioEngine.canUseWebAudio) {
+                this._outputAudioNode.gain.value = newVolume;
+            }
+        }
+
+        public switchPanningModelToHRTF() {
+            if (Engine.audioEngine.canUseWebAudio) {
+                for (var i = 0; i < this.soundCollection.length; i++) {
+                    this.soundCollection[i].switchPanningModelToHRTF();
+                }
+            }
+        }
+
+        public switchPanningModelToEqualPower() {
+            if (Engine.audioEngine.canUseWebAudio) {
+                for (var i = 0; i < this.soundCollection.length; i++) {
+                    this.soundCollection[i].switchPanningModelToEqualPower();
+                }
+            }
+        }
+
+        public connectToAnalyser(analyser: Analyser) {
+            if (this._connectedAnalyser) {
+                this._connectedAnalyser.stopDebugCanvas();
+            }
+            this._connectedAnalyser = analyser;
+            if (Engine.audioEngine.canUseWebAudio) {
+                this._outputAudioNode.disconnect();
+                this._connectedAnalyser.connectAudioNodes(this._outputAudioNode, Engine.audioEngine.masterGain);
+            }
+        }
+    }
 }

+ 91 - 91
src/Bones/babylon.bone.ts

@@ -1,92 +1,92 @@
-module BABYLON {
-    export class Bone extends Node {
-        public children = new Array<Bone>();
-        public animations = new Array<Animation>();
-
-        private _skeleton: Skeleton;
-        private _matrix: Matrix;
-        private _baseMatrix: Matrix;
-        private _worldTransform = new Matrix();
-        private _absoluteTransform = new Matrix();
-        private _invertedAbsoluteTransform = new Matrix();
-        private _parent: Bone;
-
-        constructor(public name: string, skeleton: Skeleton, parentBone: Bone, matrix: Matrix) {
-            super(name, skeleton.getScene());
-            this._skeleton = skeleton;
-            this._matrix = matrix;
-            this._baseMatrix = matrix;
-
-            skeleton.bones.push(this);
-
-            if (parentBone) {
-                this._parent = parentBone;
-                parentBone.children.push(this);
-            } else {
-                this._parent = null;
-            }
-
-            this._updateDifferenceMatrix();
-        }
-
-        // Members
-        public getParent():Bone {
-            return this._parent;
-        }
-
-        public getLocalMatrix():Matrix {
-            return this._matrix;
-        }
-
-        public getBaseMatrix(): Matrix {
-            return this._baseMatrix;
-        }
-
-        public getWorldMatrix(): Matrix {
-            return this._worldTransform;
-        }
-
-        public getInvertedAbsoluteTransform(): Matrix {
-            return this._invertedAbsoluteTransform;
-        }
-
-        public getAbsoluteMatrix(): Matrix {
-            var matrix = this._matrix.clone();
-            var parent = this._parent;
-
-            while (parent) {
-                matrix = matrix.multiply(parent.getLocalMatrix());
-                parent = parent.getParent();
-            }
-
-            return matrix;
-        }
-
-        // Methods
-        public updateMatrix(matrix: Matrix): void {
-            this._matrix = matrix;
-            this._skeleton._markAsDirty();
-
-            this._updateDifferenceMatrix();
-        }
-
-        private _updateDifferenceMatrix(): void {
-            if (this._parent) {
-                this._matrix.multiplyToRef(this._parent._absoluteTransform, this._absoluteTransform);
-            } else {
-                this._absoluteTransform.copyFrom(this._matrix);
-            }
-
-            this._absoluteTransform.invertToRef(this._invertedAbsoluteTransform);
-
-            for (var index = 0; index < this.children.length; index++) {
-                this.children[index]._updateDifferenceMatrix();
-            }
-        }
-
-        public markAsDirty(): void {
-            this._currentRenderId++;
-            this._skeleton._markAsDirty();
-        }
-    }
+module BABYLON {
+    export class Bone extends Node {
+        public children = new Array<Bone>();
+        public animations = new Array<Animation>();
+
+        private _skeleton: Skeleton;
+        private _matrix: Matrix;
+        private _baseMatrix: Matrix;
+        private _worldTransform = new Matrix();
+        private _absoluteTransform = new Matrix();
+        private _invertedAbsoluteTransform = new Matrix();
+        private _parent: Bone;
+
+        constructor(public name: string, skeleton: Skeleton, parentBone: Bone, matrix: Matrix) {
+            super(name, skeleton.getScene());
+            this._skeleton = skeleton;
+            this._matrix = matrix;
+            this._baseMatrix = matrix;
+
+            skeleton.bones.push(this);
+
+            if (parentBone) {
+                this._parent = parentBone;
+                parentBone.children.push(this);
+            } else {
+                this._parent = null;
+            }
+
+            this._updateDifferenceMatrix();
+        }
+
+        // Members
+        public getParent():Bone {
+            return this._parent;
+        }
+
+        public getLocalMatrix():Matrix {
+            return this._matrix;
+        }
+
+        public getBaseMatrix(): Matrix {
+            return this._baseMatrix;
+        }
+
+        public getWorldMatrix(): Matrix {
+            return this._worldTransform;
+        }
+
+        public getInvertedAbsoluteTransform(): Matrix {
+            return this._invertedAbsoluteTransform;
+        }
+
+        public getAbsoluteMatrix(): Matrix {
+            var matrix = this._matrix.clone();
+            var parent = this._parent;
+
+            while (parent) {
+                matrix = matrix.multiply(parent.getLocalMatrix());
+                parent = parent.getParent();
+            }
+
+            return matrix;
+        }
+
+        // Methods
+        public updateMatrix(matrix: Matrix): void {
+            this._matrix = matrix;
+            this._skeleton._markAsDirty();
+
+            this._updateDifferenceMatrix();
+        }
+
+        private _updateDifferenceMatrix(): void {
+            if (this._parent) {
+                this._matrix.multiplyToRef(this._parent._absoluteTransform, this._absoluteTransform);
+            } else {
+                this._absoluteTransform.copyFrom(this._matrix);
+            }
+
+            this._absoluteTransform.invertToRef(this._invertedAbsoluteTransform);
+
+            for (var index = 0; index < this.children.length; index++) {
+                this.children[index]._updateDifferenceMatrix();
+            }
+        }
+
+        public markAsDirty(): void {
+            this._currentRenderId++;
+            this._skeleton._markAsDirty();
+        }
+    }
 } 

+ 34 - 0
src/Bones/babylon.skeleton.js

@@ -103,6 +103,40 @@ var BABYLON;
             // Remove from scene
             this.getScene().removeSkeleton(this);
         };
+        Skeleton.prototype.serialize = function () {
+            var serializationObject = {};
+            serializationObject.name = this.name;
+            serializationObject.id = this.id;
+            serializationObject.bones = [];
+            for (var index = 0; index < this.bones.length; index++) {
+                var bone = this.bones[index];
+                var serializedBone = {
+                    parentBoneIndex: bone.getParent() ? this.bones.indexOf(bone.getParent()) : -1,
+                    name: bone.name,
+                    matrix: bone.getLocalMatrix().toArray()
+                };
+                serializationObject.bones.push(serializedBone);
+                if (bone.animations && bone.animations.length > 0) {
+                    serializedBone.animation = bone.animations[0].serialize();
+                }
+            }
+            return serializationObject;
+        };
+        Skeleton.Parse = function (parsedSkeleton, scene) {
+            var skeleton = new Skeleton(parsedSkeleton.name, parsedSkeleton.id, scene);
+            for (var index = 0; index < parsedSkeleton.bones.length; index++) {
+                var parsedBone = parsedSkeleton.bones[index];
+                var parentBone = null;
+                if (parsedBone.parentBoneIndex > -1) {
+                    parentBone = skeleton.bones[parsedBone.parentBoneIndex];
+                }
+                var bone = new BABYLON.Bone(parsedBone.name, skeleton, parentBone, BABYLON.Matrix.FromArray(parsedBone.matrix));
+                if (parsedBone.animation) {
+                    bone.animations.push(BABYLON.Animation.Parse(parsedBone.animation));
+                }
+            }
+            return skeleton;
+        };
         return Skeleton;
     })();
     BABYLON.Skeleton = Skeleton;

+ 186 - 139
src/Bones/babylon.skeleton.ts

@@ -1,140 +1,187 @@
-module BABYLON {
-    export class Skeleton {
-        public bones = new Array<Bone>();
-
-        private _scene: Scene;
-        private _isDirty = true;
-        private _transformMatrices: Float32Array;
-        private _animatables: IAnimatable[];
-        private _identity = Matrix.Identity();
-
-        private _ranges = new Array<AnimationRange>();
-
-        constructor(public name: string, public id: string, scene: Scene) {
-            this.bones = [];
-
-            this._scene = scene;
-
-            scene.skeletons.push(this);
-
-            this.prepare();
-            //make sure it will recalculate the matrix next time prepare is called.
-            this._isDirty = true;
-        }
-
-        // Members
-        public getTransformMatrices(): Float32Array {
-            return this._transformMatrices;
-        }
-
-        public getScene(): Scene {
-            return this._scene;
-        }
-
-        // Methods
-        public createAnimationRange(name: string, from: number, to: number): void {
-            this._ranges.push(new AnimationRange(name, from, to));
-        }
-
-        public deleteAnimationRange(name: string): void {
-            for (var index = 0; index < this._ranges.length; index++) {
-                if (this._ranges[index].name === name) {
-                    this._ranges.splice(index, 1);
-                    return;
-                }
-            }
-        }
-
-        public getAnimationRange(name: string): AnimationRange {
-            for (var index = 0; index < this._ranges.length; index++) {
-                if (this._ranges[index].name === name) {
-                    return this._ranges[index];
-                }
-            }
-
-            return null;
-        }
-
-        public beginAnimation(name: string, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void): void {
-            var range = this.getAnimationRange(name);
-
-            if (!range) {
-                return null;
-            }
-
-            this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
-        }
-
-        public _markAsDirty(): void {
-            this._isDirty = true;
-        }
-
-        public prepare(): void {
-            if (!this._isDirty) {
-                return;
-            }
-
-            if (!this._transformMatrices || this._transformMatrices.length !== 16 * (this.bones.length + 1)) {
-                this._transformMatrices = new Float32Array(16 * (this.bones.length + 1));
-            }
-
-            for (var index = 0; index < this.bones.length; index++) {
-                var bone = this.bones[index];
-                var parentBone = bone.getParent();
-
-                if (parentBone) {
-                    bone.getLocalMatrix().multiplyToRef(parentBone.getWorldMatrix(), bone.getWorldMatrix());
-                } else {
-                    bone.getWorldMatrix().copyFrom(bone.getLocalMatrix());
-                }
-
-                bone.getInvertedAbsoluteTransform().multiplyToArray(bone.getWorldMatrix(), this._transformMatrices, index * 16);                
-            }
-
-            this._identity.copyToArray(this._transformMatrices, this.bones.length * 16);
-
-            this._isDirty = false;
-
-            this._scene._activeBones += this.bones.length;
-        }
-
-        public getAnimatables(): IAnimatable[] {
-            if (!this._animatables || this._animatables.length !== this.bones.length) {
-                this._animatables = [];
-
-                for (var index = 0; index < this.bones.length; index++) {
-                    this._animatables.push(this.bones[index]);
-                }
-            }
-
-            return this._animatables;
-        }
-
-        public clone(name: string, id: string): Skeleton {
-            var result = new Skeleton(name, id || name, this._scene);
-
-            for (var index = 0; index < this.bones.length; index++) {
-                var source = this.bones[index];
-                var parentBone = null;
-
-                if (source.getParent()) {
-                    var parentIndex = this.bones.indexOf(source.getParent());
-                    parentBone = result.bones[parentIndex];
-                }
-
-                var bone = new Bone(source.name, result, parentBone, source.getBaseMatrix());
-                Tools.DeepCopy(source.animations, bone.animations);
-            }
-
-            return result;
-        }
-
-        public dispose() {
-            // Animations
-            this.getScene().stopAnimation(this);
-
-            // Remove from scene
-            this.getScene().removeSkeleton(this);
-        }
-    }
+module BABYLON {
+    export class Skeleton {
+        public bones = new Array<Bone>();
+
+        private _scene: Scene;
+        private _isDirty = true;
+        private _transformMatrices: Float32Array;
+        private _animatables: IAnimatable[];
+        private _identity = Matrix.Identity();
+
+        private _ranges = new Array<AnimationRange>();
+
+        constructor(public name: string, public id: string, scene: Scene) {
+            this.bones = [];
+
+            this._scene = scene;
+
+            scene.skeletons.push(this);
+
+            this.prepare();
+            //make sure it will recalculate the matrix next time prepare is called.
+            this._isDirty = true;
+        }
+
+        // Members
+        public getTransformMatrices(): Float32Array {
+            return this._transformMatrices;
+        }
+
+        public getScene(): Scene {
+            return this._scene;
+        }
+
+        // Methods
+        public createAnimationRange(name: string, from: number, to: number): void {
+            this._ranges.push(new AnimationRange(name, from, to));
+        }
+
+        public deleteAnimationRange(name: string): void {
+            for (var index = 0; index < this._ranges.length; index++) {
+                if (this._ranges[index].name === name) {
+                    this._ranges.splice(index, 1);
+                    return;
+                }
+            }
+        }
+
+        public getAnimationRange(name: string): AnimationRange {
+            for (var index = 0; index < this._ranges.length; index++) {
+                if (this._ranges[index].name === name) {
+                    return this._ranges[index];
+                }
+            }
+
+            return null;
+        }
+
+        public beginAnimation(name: string, loop?: boolean, speedRatio?: number, onAnimationEnd?: () => void): void {
+            var range = this.getAnimationRange(name);
+
+            if (!range) {
+                return null;
+            }
+
+            this._scene.beginAnimation(this, range.from, range.to, loop, speedRatio, onAnimationEnd);
+        }
+
+        public _markAsDirty(): void {
+            this._isDirty = true;
+        }
+
+        public prepare(): void {
+            if (!this._isDirty) {
+                return;
+            }
+
+            if (!this._transformMatrices || this._transformMatrices.length !== 16 * (this.bones.length + 1)) {
+                this._transformMatrices = new Float32Array(16 * (this.bones.length + 1));
+            }
+
+            for (var index = 0; index < this.bones.length; index++) {
+                var bone = this.bones[index];
+                var parentBone = bone.getParent();
+
+                if (parentBone) {
+                    bone.getLocalMatrix().multiplyToRef(parentBone.getWorldMatrix(), bone.getWorldMatrix());
+                } else {
+                    bone.getWorldMatrix().copyFrom(bone.getLocalMatrix());
+                }
+
+                bone.getInvertedAbsoluteTransform().multiplyToArray(bone.getWorldMatrix(), this._transformMatrices, index * 16);                
+            }
+
+            this._identity.copyToArray(this._transformMatrices, this.bones.length * 16);
+
+            this._isDirty = false;
+
+            this._scene._activeBones += this.bones.length;
+        }
+
+        public getAnimatables(): IAnimatable[] {
+            if (!this._animatables || this._animatables.length !== this.bones.length) {
+                this._animatables = [];
+
+                for (var index = 0; index < this.bones.length; index++) {
+                    this._animatables.push(this.bones[index]);
+                }
+            }
+
+            return this._animatables;
+        }
+
+        public clone(name: string, id: string): Skeleton {
+            var result = new Skeleton(name, id || name, this._scene);
+
+            for (var index = 0; index < this.bones.length; index++) {
+                var source = this.bones[index];
+                var parentBone = null;
+
+                if (source.getParent()) {
+                    var parentIndex = this.bones.indexOf(source.getParent());
+                    parentBone = result.bones[parentIndex];
+                }
+
+                var bone = new Bone(source.name, result, parentBone, source.getBaseMatrix());
+                Tools.DeepCopy(source.animations, bone.animations);
+            }
+
+            return result;
+        }
+
+        public dispose() {
+            // Animations
+            this.getScene().stopAnimation(this);
+
+            // Remove from scene
+            this.getScene().removeSkeleton(this);
+        }
+
+        public serialize(): any {
+            var serializationObject: any = {};
+
+            serializationObject.name = this.name;
+            serializationObject.id = this.id;
+
+            serializationObject.bones = [];
+
+            for (var index = 0; index < this.bones.length; index++) {
+                var bone = this.bones[index];
+
+                var serializedBone: any = {
+                    parentBoneIndex: bone.getParent() ? this.bones.indexOf(bone.getParent()) : -1,
+                    name: bone.name,
+                    matrix: bone.getLocalMatrix().toArray()
+                };
+
+                serializationObject.bones.push(serializedBone);
+
+                if (bone.animations && bone.animations.length > 0) {
+                    serializedBone.animation = bone.animations[0].serialize();
+                }
+            }
+            return serializationObject;
+        }
+        
+        public static Parse(parsedSkeleton: any, scene: Scene) : Skeleton {
+            var skeleton = new Skeleton(parsedSkeleton.name, parsedSkeleton.id, scene);
+
+            for (var index = 0; index < parsedSkeleton.bones.length; index++) {
+                var parsedBone = parsedSkeleton.bones[index];
+    
+                var parentBone = null;
+                if (parsedBone.parentBoneIndex > -1) {
+                    parentBone = skeleton.bones[parsedBone.parentBoneIndex];
+                }
+    
+                var bone = new Bone(parsedBone.name, skeleton, parentBone, Matrix.FromArray(parsedBone.matrix));
+    
+                if (parsedBone.animation) {
+                    bone.animations.push(Animation.Parse(parsedBone.animation));
+                }
+            }
+    
+            return skeleton;
+        }
+    }
 }

+ 49 - 49
src/Cameras/VR/babylon.vrDeviceOrientationCamera.ts

@@ -1,50 +1,50 @@
-module BABYLON {
-    export class VRDeviceOrientationFreeCamera extends FreeCamera {
-        public _alpha = 0;
-        public _beta = 0;
-        public _gamma = 0;
-    
-        private _offsetOrientation: { yaw: number; pitch: number; roll: number };
-        private _deviceOrientationHandler;
-
-        constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true) {
-            super(name, position, scene);
-
-            var metrics = VRCameraMetrics.GetDefault();
-            metrics.compensateDistortion = compensateDistortion;
-            this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
-
-            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
-        }
-
-        public _onOrientationEvent(evt: DeviceOrientationEvent): void {
-            this._alpha = +evt.alpha|0;
-            this._beta = +evt.beta|0;
-            this._gamma = +evt.gamma|0;
-
-            if (this._gamma < 0) {
-                this._gamma = 90 + this._gamma;
-            }
-            else {
-                // Incline it in the correct angle.
-                this._gamma = 270 - this._gamma;
-            }
-
-            this.rotation.x = this._gamma / 180.0 * Math.PI;   
-            this.rotation.y = -this._alpha / 180.0 * Math.PI;   
-            this.rotation.z = this._beta / 180.0 * Math.PI;     
-        }
-
-        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-            super.attachControl(element, noPreventDefault);
-
-            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
-        }
-
-        public detachControl(element: HTMLElement): void {
-            super.detachControl(element);
-
-            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
-        }
-    }
+module BABYLON {
+    export class VRDeviceOrientationFreeCamera extends FreeCamera {
+        public _alpha = 0;
+        public _beta = 0;
+        public _gamma = 0;
+    
+        private _offsetOrientation: { yaw: number; pitch: number; roll: number };
+        private _deviceOrientationHandler;
+
+        constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true) {
+            super(name, position, scene);
+
+            var metrics = VRCameraMetrics.GetDefault();
+            metrics.compensateDistortion = compensateDistortion;
+            this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
+
+            this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
+        }
+
+        public _onOrientationEvent(evt: DeviceOrientationEvent): void {
+            this._alpha = +evt.alpha|0;
+            this._beta = +evt.beta|0;
+            this._gamma = +evt.gamma|0;
+
+            if (this._gamma < 0) {
+                this._gamma = 90 + this._gamma;
+            }
+            else {
+                // Incline it in the correct angle.
+                this._gamma = 270 - this._gamma;
+            }
+
+            this.rotation.x = this._gamma / 180.0 * Math.PI;   
+            this.rotation.y = -this._alpha / 180.0 * Math.PI;   
+            this.rotation.z = this._beta / 180.0 * Math.PI;     
+        }
+
+        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+            super.attachControl(element, noPreventDefault);
+
+            window.addEventListener("deviceorientation", this._deviceOrientationHandler);
+        }
+
+        public detachControl(element: HTMLElement): void {
+            super.detachControl(element);
+
+            window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
+        }
+    }
 }

+ 80 - 80
src/Cameras/VR/babylon.webVRCamera.ts

@@ -1,81 +1,81 @@
-declare var HMDVRDevice;
-declare var PositionSensorVRDevice;
-
-module BABYLON {
-    export class WebVRFreeCamera extends FreeCamera {
-        public _hmdDevice = null;
-        public _sensorDevice = null;
-        public _cacheState = null;
-        public _cacheQuaternion = new Quaternion();
-        public _cacheRotation = Vector3.Zero();
-        public _vrEnabled = false;
-
-        constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true) {
-            super(name, position, scene);
-            
-            var metrics = VRCameraMetrics.GetDefault();
-            metrics.compensateDistortion = compensateDistortion;
-            this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
-
-            this._getWebVRDevices = this._getWebVRDevices.bind(this);
-        }
-
-        private _getWebVRDevices(devices: Array<any>): void {
-            var size = devices.length;
-            var i = 0;
-
-            // Reset devices.
-            this._sensorDevice = null;
-            this._hmdDevice = null;
-
-            // Search for a HmdDevice.
-            while (i < size && this._hmdDevice === null) {
-                if (devices[i] instanceof HMDVRDevice) {
-                    this._hmdDevice = devices[i];
-                }
-                i++;
-            }
-
-            i = 0;
-
-            while (i < size && this._sensorDevice === null) {
-                if (devices[i] instanceof PositionSensorVRDevice && (!this._hmdDevice || devices[i].hardwareUnitId === this._hmdDevice.hardwareUnitId)) {
-                    this._sensorDevice = devices[i];
-                }
-                i++;
-            }
-
-            this._vrEnabled = this._sensorDevice && this._hmdDevice ? true : false;
-        }
-
-        public _checkInputs(): void {
-            if (this._vrEnabled) {
-                this._cacheState = this._sensorDevice.getState();
-                this._cacheQuaternion.copyFromFloats(this._cacheState.orientation.x, this._cacheState.orientation.y, this._cacheState.orientation.z, this._cacheState.orientation.w);
-                this._cacheQuaternion.toEulerAnglesToRef(this._cacheRotation);
-
-                this.rotation.x = -this._cacheRotation.z;
-                this.rotation.y = -this._cacheRotation.y;
-                this.rotation.z = this._cacheRotation.x;
-            }
-
-            super._checkInputs();
-        }
-
-        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
-            super.attachControl(element, noPreventDefault);
-
-            if (navigator.getVRDevices) {
-                navigator.getVRDevices().then(this._getWebVRDevices);
-            }
-            else if (navigator.mozGetVRDevices) {
-                navigator.mozGetVRDevices(this._getWebVRDevices);
-            }
-        }
-
-        public detachControl(element: HTMLElement): void {
-            super.detachControl(element);
-            this._vrEnabled = false;
-        }
-    }
+declare var HMDVRDevice;
+declare var PositionSensorVRDevice;
+
+module BABYLON {
+    export class WebVRFreeCamera extends FreeCamera {
+        public _hmdDevice = null;
+        public _sensorDevice = null;
+        public _cacheState = null;
+        public _cacheQuaternion = new Quaternion();
+        public _cacheRotation = Vector3.Zero();
+        public _vrEnabled = false;
+
+        constructor(name: string, position: Vector3, scene: Scene, compensateDistortion = true) {
+            super(name, position, scene);
+            
+            var metrics = VRCameraMetrics.GetDefault();
+            metrics.compensateDistortion = compensateDistortion;
+            this.setCameraRigMode(Camera.RIG_MODE_VR, { vrCameraMetrics: metrics });
+
+            this._getWebVRDevices = this._getWebVRDevices.bind(this);
+        }
+
+        private _getWebVRDevices(devices: Array<any>): void {
+            var size = devices.length;
+            var i = 0;
+
+            // Reset devices.
+            this._sensorDevice = null;
+            this._hmdDevice = null;
+
+            // Search for a HmdDevice.
+            while (i < size && this._hmdDevice === null) {
+                if (devices[i] instanceof HMDVRDevice) {
+                    this._hmdDevice = devices[i];
+                }
+                i++;
+            }
+
+            i = 0;
+
+            while (i < size && this._sensorDevice === null) {
+                if (devices[i] instanceof PositionSensorVRDevice && (!this._hmdDevice || devices[i].hardwareUnitId === this._hmdDevice.hardwareUnitId)) {
+                    this._sensorDevice = devices[i];
+                }
+                i++;
+            }
+
+            this._vrEnabled = this._sensorDevice && this._hmdDevice ? true : false;
+        }
+
+        public _checkInputs(): void {
+            if (this._vrEnabled) {
+                this._cacheState = this._sensorDevice.getState();
+                this._cacheQuaternion.copyFromFloats(this._cacheState.orientation.x, this._cacheState.orientation.y, this._cacheState.orientation.z, this._cacheState.orientation.w);
+                this._cacheQuaternion.toEulerAnglesToRef(this._cacheRotation);
+
+                this.rotation.x = -this._cacheRotation.z;
+                this.rotation.y = -this._cacheRotation.y;
+                this.rotation.z = this._cacheRotation.x;
+            }
+
+            super._checkInputs();
+        }
+
+        public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
+            super.attachControl(element, noPreventDefault);
+
+            if (navigator.getVRDevices) {
+                navigator.getVRDevices().then(this._getWebVRDevices);
+            }
+            else if (navigator.mozGetVRDevices) {
+                navigator.mozGetVRDevices(this._getWebVRDevices);
+            }
+        }
+
+        public detachControl(element: HTMLElement): void {
+            super.detachControl(element);
+            this._vrEnabled = false;
+        }
+    }
 }

+ 36 - 36
src/Cameras/babylon.anaglyphCamera.js

@@ -1,37 +1,37 @@
-var __extends = this.__extends || function (d, b) {
-    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
-    function __() { this.constructor = d; }
-    __.prototype = b.prototype;
-    d.prototype = new __();
-};
-var BABYLON;
-(function (BABYLON) {
-    var AnaglyphFreeCamera = (function (_super) {
-        __extends(AnaglyphFreeCamera, _super);
-        function AnaglyphFreeCamera(name, position, eyeSpace, scene) {
-            _super.call(this, name, position, scene);
-            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
-        }
-        return AnaglyphFreeCamera;
-    })(BABYLON.FreeCamera);
-    BABYLON.AnaglyphFreeCamera = AnaglyphFreeCamera;
-    var AnaglyphArcRotateCamera = (function (_super) {
-        __extends(AnaglyphArcRotateCamera, _super);
-        function AnaglyphArcRotateCamera(name, alpha, beta, radius, target, eyeSpace, scene) {
-            _super.call(this, name, alpha, beta, radius, target, scene);
-            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
-        }
-        return AnaglyphArcRotateCamera;
-    })(BABYLON.ArcRotateCamera);
-    BABYLON.AnaglyphArcRotateCamera = AnaglyphArcRotateCamera;
-    var AnaglyphGamepadCamera = (function (_super) {
-        __extends(AnaglyphGamepadCamera, _super);
-        function AnaglyphGamepadCamera(name, position, eyeSpace, scene) {
-            _super.call(this, name, position, scene);
-            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
-        }
-        return AnaglyphGamepadCamera;
-    })(BABYLON.GamepadCamera);
-    BABYLON.AnaglyphGamepadCamera = AnaglyphGamepadCamera;
-})(BABYLON || (BABYLON = {}));
+var __extends = this.__extends || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    __.prototype = b.prototype;
+    d.prototype = new __();
+};
+var BABYLON;
+(function (BABYLON) {
+    var AnaglyphFreeCamera = (function (_super) {
+        __extends(AnaglyphFreeCamera, _super);
+        function AnaglyphFreeCamera(name, position, eyeSpace, scene) {
+            _super.call(this, name, position, scene);
+            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
+        }
+        return AnaglyphFreeCamera;
+    })(BABYLON.FreeCamera);
+    BABYLON.AnaglyphFreeCamera = AnaglyphFreeCamera;
+    var AnaglyphArcRotateCamera = (function (_super) {
+        __extends(AnaglyphArcRotateCamera, _super);
+        function AnaglyphArcRotateCamera(name, alpha, beta, radius, target, eyeSpace, scene) {
+            _super.call(this, name, alpha, beta, radius, target, scene);
+            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
+        }
+        return AnaglyphArcRotateCamera;
+    })(BABYLON.ArcRotateCamera);
+    BABYLON.AnaglyphArcRotateCamera = AnaglyphArcRotateCamera;
+    var AnaglyphGamepadCamera = (function (_super) {
+        __extends(AnaglyphGamepadCamera, _super);
+        function AnaglyphGamepadCamera(name, position, eyeSpace, scene) {
+            _super.call(this, name, position, scene);
+            this.setSubCameraMode(BABYLON.Camera.SUB_CAMERA_MODE_ANAGLYPH, eyeSpace);
+        }
+        return AnaglyphGamepadCamera;
+    })(BABYLON.GamepadCamera);
+    BABYLON.AnaglyphGamepadCamera = AnaglyphGamepadCamera;
+})(BABYLON || (BABYLON = {}));
 //# sourceMappingURL=babylon.anaglyphCamera.js.map

+ 15 - 1
src/Cameras/babylon.arcRotateCamera.js

@@ -58,7 +58,7 @@ var BABYLON;
                     _this._previousPosition.copyFrom(_this.position);
                 }
                 else {
-                    _this.setPosition(_this.position);
+                    _this.setPosition(newPosition);
                     if (_this.onCollide) {
                         _this.onCollide(collidedMesh);
                     }
@@ -553,6 +553,20 @@ var BABYLON;
             }
             _super.prototype._updateRigCameras.call(this);
         };
+        ArcRotateCamera.prototype.serialize = function () {
+            var serializationObject = _super.prototype.serialize.call(this);
+            if (this.target instanceof BABYLON.Vector3) {
+                serializationObject.target = this.target.asArray();
+            }
+            if (this.target && this.target.id) {
+                serializationObject.lockedTargetId = this.target.id;
+            }
+            serializationObject.checkCollisions = this.checkCollisions;
+            serializationObject.alpha = this.alpha;
+            serializationObject.beta = this.beta;
+            serializationObject.radius = this.radius;
+            return serializationObject;
+        };
         return ArcRotateCamera;
     })(BABYLON.TargetCamera);
     BABYLON.ArcRotateCamera = ArcRotateCamera;

Plik diff jest za duży
+ 672 - 654
src/Cameras/babylon.arcRotateCamera.ts


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

@@ -516,6 +516,135 @@ var BABYLON;
                 this._rigCameras[0].viewport = this._rigCameras[1].viewport = this.viewport;
             }
         };
+        Camera.prototype.serialize = function () {
+            var serializationObject = {};
+            serializationObject.name = this.name;
+            serializationObject.tags = BABYLON.Tags.GetTags(this);
+            serializationObject.id = this.id;
+            serializationObject.position = this.position.asArray();
+            serializationObject.type = BABYLON.Tools.GetConstructorName(this);
+            // Parent
+            if (this.parent) {
+                serializationObject.parentId = this.parent.id;
+            }
+            serializationObject.fov = this.fov;
+            serializationObject.minZ = this.minZ;
+            serializationObject.maxZ = this.maxZ;
+            serializationObject.inertia = this.inertia;
+            // Animations
+            BABYLON.Animation.AppendSerializedAnimations(this, serializationObject);
+            // Layer mask
+            serializationObject.layerMask = this.layerMask;
+            return serializationObject;
+        };
+        Camera.Parse = function (parsedCamera, scene) {
+            var camera;
+            var position = BABYLON.Vector3.FromArray(parsedCamera.position);
+            var lockedTargetMesh = (parsedCamera.lockedTargetId) ? scene.getLastMeshByID(parsedCamera.lockedTargetId) : null;
+            var interaxial_distance;
+            if (parsedCamera.type === "AnaglyphArcRotateCamera" || parsedCamera.type === "ArcRotateCamera") {
+                var alpha = parsedCamera.alpha;
+                var beta = parsedCamera.beta;
+                var radius = parsedCamera.radius;
+                if (parsedCamera.type === "AnaglyphArcRotateCamera") {
+                    interaxial_distance = parsedCamera.interaxial_distance;
+                    camera = new BABYLON.AnaglyphArcRotateCamera(parsedCamera.name, alpha, beta, radius, lockedTargetMesh, interaxial_distance, scene);
+                }
+                else {
+                    camera = new BABYLON.ArcRotateCamera(parsedCamera.name, alpha, beta, radius, lockedTargetMesh, scene);
+                }
+            }
+            else if (parsedCamera.type === "AnaglyphFreeCamera") {
+                interaxial_distance = parsedCamera.interaxial_distance;
+                camera = new BABYLON.AnaglyphFreeCamera(parsedCamera.name, position, interaxial_distance, scene);
+            }
+            else if (parsedCamera.type === "DeviceOrientationCamera") {
+                camera = new BABYLON.DeviceOrientationCamera(parsedCamera.name, position, scene);
+            }
+            else if (parsedCamera.type === "FollowCamera") {
+                camera = new BABYLON.FollowCamera(parsedCamera.name, position, scene);
+                camera.heightOffset = parsedCamera.heightOffset;
+                camera.radius = parsedCamera.radius;
+                camera.rotationOffset = parsedCamera.rotationOffset;
+                if (lockedTargetMesh)
+                    camera.target = lockedTargetMesh;
+            }
+            else if (parsedCamera.type === "GamepadCamera") {
+                camera = new BABYLON.GamepadCamera(parsedCamera.name, position, scene);
+            }
+            else if (parsedCamera.type === "TouchCamera") {
+                camera = new BABYLON.TouchCamera(parsedCamera.name, position, scene);
+            }
+            else if (parsedCamera.type === "VirtualJoysticksCamera") {
+                camera = new BABYLON.VirtualJoysticksCamera(parsedCamera.name, position, scene);
+            }
+            else if (parsedCamera.type === "WebVRFreeCamera") {
+                camera = new BABYLON.WebVRFreeCamera(parsedCamera.name, position, scene);
+            }
+            else if (parsedCamera.type === "VRDeviceOrientationFreeCamera") {
+                camera = new BABYLON.VRDeviceOrientationFreeCamera(parsedCamera.name, position, scene);
+            }
+            else {
+                // Free Camera is the default value
+                camera = new BABYLON.FreeCamera(parsedCamera.name, position, scene);
+            }
+            // apply 3d rig, when found
+            if (parsedCamera.cameraRigMode) {
+                var rigParams = (parsedCamera.interaxial_distance) ? { interaxialDistance: parsedCamera.interaxial_distance } : {};
+                camera.setCameraRigMode(parsedCamera.cameraRigMode, rigParams);
+            }
+            // Test for lockedTargetMesh & FreeCamera outside of if-else-if nest, since things like GamepadCamera extend FreeCamera
+            if (lockedTargetMesh && camera instanceof BABYLON.FreeCamera) {
+                camera.lockedTarget = lockedTargetMesh;
+            }
+            camera.id = parsedCamera.id;
+            BABYLON.Tags.AddTagsTo(camera, parsedCamera.tags);
+            // Parent
+            if (parsedCamera.parentId) {
+                camera._waitingParentId = parsedCamera.parentId;
+            }
+            // Target
+            if (parsedCamera.target) {
+                if (camera.setTarget) {
+                    camera.setTarget(BABYLON.Vector3.FromArray(parsedCamera.target));
+                }
+                else {
+                    //For ArcRotate
+                    camera.target = BABYLON.Vector3.FromArray(parsedCamera.target);
+                }
+            }
+            else {
+                camera.rotation = BABYLON.Vector3.FromArray(parsedCamera.rotation);
+            }
+            camera.fov = parsedCamera.fov;
+            camera.minZ = parsedCamera.minZ;
+            camera.maxZ = parsedCamera.maxZ;
+            camera.speed = parsedCamera.speed;
+            camera.inertia = parsedCamera.inertia;
+            camera.checkCollisions = parsedCamera.checkCollisions;
+            camera.applyGravity = parsedCamera.applyGravity;
+            if (parsedCamera.ellipsoid) {
+                camera.ellipsoid = BABYLON.Vector3.FromArray(parsedCamera.ellipsoid);
+            }
+            // Animations
+            if (parsedCamera.animations) {
+                for (var animationIndex = 0; animationIndex < parsedCamera.animations.length; animationIndex++) {
+                    var parsedAnimation = parsedCamera.animations[animationIndex];
+                    camera.animations.push(BABYLON.Animation.Parse(parsedAnimation));
+                }
+            }
+            if (parsedCamera.autoAnimate) {
+                scene.beginAnimation(camera, parsedCamera.autoAnimateFrom, parsedCamera.autoAnimateTo, parsedCamera.autoAnimateLoop, 1.0);
+            }
+            // Layer Mask
+            if (parsedCamera.layerMask && (!isNaN(parsedCamera.layerMask))) {
+                camera.layerMask = Math.abs(parseInt(parsedCamera.layerMask));
+            }
+            else {
+                camera.layerMask = 0x0FFFFFFF;
+            }
+            return camera;
+        };
         // Statics
         Camera._PERSPECTIVE_CAMERA = 0;
         Camera._ORTHOGRAPHIC_CAMERA = 1;

Plik diff jest za duży
+ 738 - 589
src/Cameras/babylon.camera.ts


+ 1 - 1
src/Cameras/babylon.deviceOrientationCamera.js

@@ -44,7 +44,7 @@ var BABYLON;
             window.addEventListener("deviceorientation", this._orientationChanged);
         };
         DeviceOrientationCamera.prototype.detachControl = function (canvas) {
-            if (this._attachedCanvas != canvas) {
+            if (this._attachedCanvas !== canvas) {
                 return;
             }
             window.removeEventListener("deviceorientation", this._orientationChanged);

+ 77 - 77
src/Cameras/babylon.deviceOrientationCamera.ts

@@ -1,78 +1,78 @@
-module BABYLON {
-    // We're mainly based on the logic defined into the FreeCamera code
-    export class DeviceOrientationCamera extends FreeCamera {
-        private _offsetX: number = null;
-        private _offsetY: number = null;
-        private _orientationGamma: number = 0;
-        private _orientationBeta: number = 0;
-        private _initialOrientationGamma: number = 0;
-        private _initialOrientationBeta: number = 0;
-        private _attachedCanvas: HTMLCanvasElement;
-        private _orientationChanged: (e: DeviceOrientationEvent) => any;
-
-        public angularSensibility: number = 10000.0;
-        public moveSensibility: number = 50.0;
-
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
-
-            window.addEventListener("resize", () => {
-                this._initialOrientationGamma = null;
-            }, false);
-        }
-
-        public attachControl(canvas: HTMLCanvasElement, noPreventDefault: boolean): void {
-            if (this._attachedCanvas) {
-                return;
-            }
-            this._attachedCanvas = canvas;
-
-            if (!this._orientationChanged) {
-                this._orientationChanged = (evt) => {
-
-                    if (!this._initialOrientationGamma) {
-                            this._initialOrientationGamma = evt.gamma;
-                            this._initialOrientationBeta = evt.beta;
-                    }
-
-                    this._orientationGamma = evt.gamma;
-                    this._orientationBeta = evt.beta;
- 
-                    this._offsetY = (this._initialOrientationBeta - this._orientationBeta);
-                    this._offsetX = (this._initialOrientationGamma - this._orientationGamma);
-                };
-            }
-
-            window.addEventListener("deviceorientation", this._orientationChanged);
-        }
-
-        public detachControl(canvas: HTMLCanvasElement): void {
-            if (this._attachedCanvas != canvas) {
-                return;
-            }
-
-            window.removeEventListener("deviceorientation", this._orientationChanged);
-
-            this._attachedCanvas = null;
-            this._orientationGamma = 0;
-            this._orientationBeta = 0;
-            this._initialOrientationGamma = 0;
-            this._initialOrientationBeta = 0;
-        }
-
-        public _checkInputs(): void {
-            if (!this._offsetX) {
-                return;
-            }
-            this.cameraRotation.y -= this._offsetX / this.angularSensibility;
-
-            var speed = this._computeLocalCameraSpeed();
-            var direction = new Vector3(0, 0, speed * this._offsetY / this.moveSensibility);
-
-            Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
-            this.cameraDirection.addInPlace(Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
-
-            super._checkInputs();
-        }
-    }
+module BABYLON {
+    // We're mainly based on the logic defined into the FreeCamera code
+    export class DeviceOrientationCamera extends FreeCamera {
+        private _offsetX: number = null;
+        private _offsetY: number = null;
+        private _orientationGamma: number = 0;
+        private _orientationBeta: number = 0;
+        private _initialOrientationGamma: number = 0;
+        private _initialOrientationBeta: number = 0;
+        private _attachedCanvas: HTMLCanvasElement;
+        private _orientationChanged: (e: DeviceOrientationEvent) => any;
+
+        public angularSensibility: number = 10000.0;
+        public moveSensibility: number = 50.0;
+
+        constructor(name: string, position: Vector3, scene: Scene) {
+            super(name, position, scene);
+
+            window.addEventListener("resize", () => {
+                this._initialOrientationGamma = null;
+            }, false);
+        }
+
+        public attachControl(canvas: HTMLCanvasElement, noPreventDefault: boolean): void {
+            if (this._attachedCanvas) {
+                return;
+            }
+            this._attachedCanvas = canvas;
+
+            if (!this._orientationChanged) {
+                this._orientationChanged = (evt) => {
+
+                    if (!this._initialOrientationGamma) {
+                            this._initialOrientationGamma = evt.gamma;
+                            this._initialOrientationBeta = evt.beta;
+                    }
+
+                    this._orientationGamma = evt.gamma;
+                    this._orientationBeta = evt.beta;
+ 
+                    this._offsetY = (this._initialOrientationBeta - this._orientationBeta);
+                    this._offsetX = (this._initialOrientationGamma - this._orientationGamma);
+                };
+            }
+
+            window.addEventListener("deviceorientation", this._orientationChanged);
+        }
+
+        public detachControl(canvas: HTMLCanvasElement): void {
+            if (this._attachedCanvas !== canvas) {
+                return;
+            }
+
+            window.removeEventListener("deviceorientation", this._orientationChanged);
+
+            this._attachedCanvas = null;
+            this._orientationGamma = 0;
+            this._orientationBeta = 0;
+            this._initialOrientationGamma = 0;
+            this._initialOrientationBeta = 0;
+        }
+
+        public _checkInputs(): void {
+            if (!this._offsetX) {
+                return;
+            }
+            this.cameraRotation.y -= this._offsetX / this.angularSensibility;
+
+            var speed = this._computeLocalCameraSpeed();
+            var direction = new Vector3(0, 0, speed * this._offsetY / this.moveSensibility);
+
+            Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraRotationMatrix);
+            this.cameraDirection.addInPlace(Vector3.TransformCoordinates(direction, this._cameraRotationMatrix));
+
+            super._checkInputs();
+        }
+    }
 }

+ 12 - 0
src/Cameras/babylon.followCamera.js

@@ -55,6 +55,13 @@ var BABYLON;
             _super.prototype._checkInputs.call(this);
             this.follow(this.target);
         };
+        FollowCamera.prototype.serialize = function () {
+            var serializationObject = _super.prototype.serialize.call(this);
+            serializationObject.radius = this.radius;
+            serializationObject.heightOffset = this.heightOffset;
+            serializationObject.rotationOffset = this.rotationOffset;
+            return serializationObject;
+        };
         return FollowCamera;
     })(BABYLON.TargetCamera);
     BABYLON.FollowCamera = FollowCamera;
@@ -80,6 +87,11 @@ var BABYLON;
             _super.prototype._checkInputs.call(this);
             this.follow();
         };
+        ArcFollowCamera.prototype.serialize = function () {
+            var serializationObject = _super.prototype.serialize.call(this);
+            serializationObject.radius = this.radius;
+            return serializationObject;
+        };
         return ArcFollowCamera;
     })(BABYLON.TargetCamera);
     BABYLON.ArcFollowCamera = ArcFollowCamera;

+ 107 - 89
src/Cameras/babylon.followCamera.ts

@@ -1,89 +1,107 @@
-module BABYLON {
-    export class FollowCamera extends TargetCamera {
-
-        public radius: number = 12;
-        public rotationOffset: number = 0;
-        public heightOffset: number = 4;
-        public cameraAcceleration: number = 0.05;
-        public maxCameraSpeed: number = 20;
-        public target: AbstractMesh;
-
-        constructor(name: string, position: Vector3, scene: Scene) {
-            super(name, position, scene);
-        }
-
-        private getRadians(degrees): number {
-            return degrees * Math.PI / 180;
-        }
-
-        private follow(cameraTarget: AbstractMesh) {
-            if (!cameraTarget)
-                return;
-
-            var yRotation;
-            if (cameraTarget.rotationQuaternion) {
-                var rotMatrix = new Matrix();
-                cameraTarget.rotationQuaternion.toRotationMatrix(rotMatrix);
-                yRotation = Math.atan2(rotMatrix.m[8], rotMatrix.m[10]);
-            } else {
-                yRotation = cameraTarget.rotation.y;
-            }
-            var radians = this.getRadians(this.rotationOffset) + yRotation;
-            var targetX: number = cameraTarget.position.x + Math.sin(radians) * this.radius;
-
-            var targetZ: number = cameraTarget.position.z + Math.cos(radians) * this.radius;
-            var dx: number = targetX - this.position.x;
-            var dy: number = (cameraTarget.position.y + this.heightOffset) - this.position.y;
-            var dz: number = (targetZ) - this.position.z;
-            var vx: number = dx * this.cameraAcceleration * 2;//this is set to .05
-            var vy: number = dy * this.cameraAcceleration;
-            var vz: number = dz * this.cameraAcceleration * 2;
-
-            if (vx > this.maxCameraSpeed || vx < -this.maxCameraSpeed) {
-                vx = vx < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
-            }
-
-            if (vy > this.maxCameraSpeed || vy < -this.maxCameraSpeed) {
-                vy = vy < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
-            }
-
-            if (vz > this.maxCameraSpeed || vz < -this.maxCameraSpeed) {
-                vz = vz < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
-            }
-
-            this.position = new Vector3(this.position.x + vx, this.position.y + vy, this.position.z + vz);
-            this.setTarget(cameraTarget.position);
-        }
-
-        public _checkInputs(): void {
-            super._checkInputs();
-            this.follow(this.target);
-        }
-    }
-
-    export class ArcFollowCamera extends TargetCamera {
-
-        private _cartesianCoordinates: Vector3 = Vector3.Zero();
-
-        constructor(name: string, public alpha: number, public beta: number, public radius: number, public target: AbstractMesh, scene: Scene) {
-            super(name, Vector3.Zero(), scene);
-            this.follow();
-        }
-
-        private follow(): void {
-            this._cartesianCoordinates.x = this.radius * Math.cos(this.alpha) * Math.cos(this.beta);
-            this._cartesianCoordinates.y = this.radius * Math.sin(this.beta);
-            this._cartesianCoordinates.z = this.radius * Math.sin(this.alpha) * Math.cos(this.beta);
-
-            this.position = this.target.position.add(this._cartesianCoordinates);
-            this.setTarget(this.target.position);
-        }
-
-        public _checkInputs(): void {
-            super._checkInputs();
-            this.follow();
-        }
-    }
-}
-
-
+module BABYLON {
+    export class FollowCamera extends TargetCamera {
+
+        public radius: number = 12;
+        public rotationOffset: number = 0;
+        public heightOffset: number = 4;
+        public cameraAcceleration: number = 0.05;
+        public maxCameraSpeed: number = 20;
+        public target: AbstractMesh;
+
+        constructor(name: string, position: Vector3, scene: Scene) {
+            super(name, position, scene);
+        }
+
+        private getRadians(degrees): number {
+            return degrees * Math.PI / 180;
+        }
+
+        private follow(cameraTarget: AbstractMesh) {
+            if (!cameraTarget)
+                return;
+
+            var yRotation;
+            if (cameraTarget.rotationQuaternion) {
+                var rotMatrix = new Matrix();
+                cameraTarget.rotationQuaternion.toRotationMatrix(rotMatrix);
+                yRotation = Math.atan2(rotMatrix.m[8], rotMatrix.m[10]);
+            } else {
+                yRotation = cameraTarget.rotation.y;
+            }
+            var radians = this.getRadians(this.rotationOffset) + yRotation;
+            var targetX: number = cameraTarget.position.x + Math.sin(radians) * this.radius;
+
+            var targetZ: number = cameraTarget.position.z + Math.cos(radians) * this.radius;
+            var dx: number = targetX - this.position.x;
+            var dy: number = (cameraTarget.position.y + this.heightOffset) - this.position.y;
+            var dz: number = (targetZ) - this.position.z;
+            var vx: number = dx * this.cameraAcceleration * 2;//this is set to .05
+            var vy: number = dy * this.cameraAcceleration;
+            var vz: number = dz * this.cameraAcceleration * 2;
+
+            if (vx > this.maxCameraSpeed || vx < -this.maxCameraSpeed) {
+                vx = vx < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
+            }
+
+            if (vy > this.maxCameraSpeed || vy < -this.maxCameraSpeed) {
+                vy = vy < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
+            }
+
+            if (vz > this.maxCameraSpeed || vz < -this.maxCameraSpeed) {
+                vz = vz < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
+            }
+
+            this.position = new Vector3(this.position.x + vx, this.position.y + vy, this.position.z + vz);
+            this.setTarget(cameraTarget.position);
+        }
+
+        public _checkInputs(): void {
+            super._checkInputs();
+            this.follow(this.target);
+        }
+
+        public serialize(): any {
+            var serializationObject = super.serialize();
+       
+            serializationObject.radius = this.radius;
+            serializationObject.heightOffset = this.heightOffset;
+            serializationObject.rotationOffset = this.rotationOffset;
+       
+            return serializationObject;
+        }
+    }
+
+    export class ArcFollowCamera extends TargetCamera {
+
+        private _cartesianCoordinates: Vector3 = Vector3.Zero();
+
+        constructor(name: string, public alpha: number, public beta: number, public radius: number, public target: AbstractMesh, scene: Scene) {
+            super(name, Vector3.Zero(), scene);
+            this.follow();
+        }
+
+        private follow(): void {
+            this._cartesianCoordinates.x = this.radius * Math.cos(this.alpha) * Math.cos(this.beta);
+            this._cartesianCoordinates.y = this.radius * Math.sin(this.beta);
+            this._cartesianCoordinates.z = this.radius * Math.sin(this.alpha) * Math.cos(this.beta);
+
+            this.position = this.target.position.add(this._cartesianCoordinates);
+            this.setTarget(this.target.position);
+        }
+
+        public _checkInputs(): void {
+            super._checkInputs();
+            this.follow();
+        }
+
+        public serialize(): any {
+            var serializationObject = super.serialize();
+
+            serializationObject.radius = this.radius;
+
+            return serializationObject;
+        }
+    }
+}
+
+

+ 8 - 1
src/Cameras/babylon.freeCamera.js

@@ -148,7 +148,7 @@ var BABYLON;
             ]);
         };
         FreeCamera.prototype.detachControl = function (element) {
-            if (this._attachedElement != element) {
+            if (this._attachedElement !== element) {
                 return;
             }
             element.removeEventListener("mousedown", this._onMouseDown);
@@ -222,6 +222,13 @@ var BABYLON;
                 this.position.addInPlace(this.cameraDirection);
             }
         };
+        FreeCamera.prototype.serialize = function () {
+            var serializationObject = _super.prototype.serialize.call(this);
+            serializationObject.checkCollisions = this.checkCollisions;
+            serializationObject.applyGravity = this.applyGravity;
+            serializationObject.ellipsoid = this.ellipsoid.asArray();
+            return serializationObject;
+        };
         return FreeCamera;
     })(BABYLON.TargetCamera);
     BABYLON.FreeCamera = FreeCamera;

+ 0 - 0
src/Cameras/babylon.freeCamera.ts


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików