Deltakosh 12 éve
szülő
commit
944cfb41aa
100 módosított fájl, 10021 hozzáadás és 1263 törlés
  1. 6 8
      Babylon/Animations/babylon.animatable.js
  2. 16 2
      Babylon/Animations/babylon.animation.js
  3. 73 0
      Babylon/Bones/babylon.bone.js
  4. 81 0
      Babylon/Bones/babylon.skeleton.js
  5. 138 101
      Babylon/Cameras/babylon.arcRotateCamera.js
  6. 1 1
      Babylon/Cameras/babylon.camera.js
  7. 30 7
      Babylon/Cameras/babylon.freeCamera.js
  8. 82 53
      Babylon/Cameras/babylon.touchCamera.js
  9. 52 27
      Babylon/Lights/Shadows/babylon.shadowGenerator.js
  10. 4 0
      Babylon/Materials/babylon.effect.js
  11. 13 0
      Babylon/Materials/babylon.multiMaterial.js
  12. 69 17
      Babylon/Materials/babylon.standardMaterial.js
  13. 1 1
      Babylon/Materials/textures/babylon.baseTexture.js
  14. 2 2
      Babylon/Materials/textures/babylon.cubeTexture.js
  15. 17 0
      Babylon/Materials/textures/babylon.dynamicTexture.js
  16. 17 1
      Babylon/Materials/textures/babylon.mirrorTexture.js
  17. 16 1
      Babylon/Materials/textures/babylon.renderTargetTexture.js
  18. 25 0
      Babylon/Materials/textures/babylon.texture.js
  19. 3 3
      Babylon/Materials/textures/babylon.videoTexture.js
  20. 117 32
      Babylon/Mesh/babylon.mesh.js
  21. 18 5
      Babylon/Mesh/babylon.vertexBuffer.js
  22. 1 1
      Babylon/Particles/babylon.particleSystem.js
  23. 6 0
      Babylon/PostProcess/babylon.postProcess.js
  24. 20 0
      Babylon/PostProcess/babylon.postProcessManager.js
  25. 26 3
      Babylon/Shaders/default.vertex.fx
  26. 25 3
      Babylon/Shaders/iedefault.vertex.fx
  27. 23 0
      Babylon/Shaders/shadowMap.vertex.fx
  28. 14 13
      Babylon/Sprites/babylon.sprite.js
  29. 6 2
      Babylon/Sprites/babylon.spriteManager.js
  30. 514 0
      Babylon/Tools/babylon.database.js
  31. 218 163
      Babylon/Tools/babylon.math.js
  32. 112 21
      Babylon/Tools/babylon.sceneLoader.js
  33. 69 15
      Babylon/Tools/babylon.tools.js
  34. 61 41
      Babylon/babylon.engine.js
  35. 102 31
      Babylon/babylon.scene.js
  36. 908 709
      Exporters/Blender/io_export_babylon.py
  37. 6 0
      Exporters/FBX - OBJ/BabylonExport/App.config
  38. 761 0
      Exporters/FBX - OBJ/BabylonExport/BabylonExport.csproj
  39. BIN
      Exporters/FBX - OBJ/BabylonExport/DirectShow.Net.dll
  40. 35 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonAnimation.cs
  41. 14 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonAnimationKey.cs
  42. 24 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonBone.cs
  43. 61 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonCamera.cs
  44. 39 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonLight.cs
  45. 68 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonMaterial.cs
  46. 111 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonMesh.cs
  47. 17 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonMultiMaterial.cs
  48. 86 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonParticleSystem.cs
  49. 160 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonScene.cs
  50. 22 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonShadowGenerator.cs
  51. 18 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonSkeleton.cs
  52. 24 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonSubMesh.cs
  53. 84 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonTexture.cs
  54. 15 0
      Exporters/FBX - OBJ/BabylonExport/Entities/IDumpable.cs
  55. 14 0
      Exporters/FBX - OBJ/BabylonExport/Entities/IQueryable.cs
  56. 138 0
      Exporters/FBX - OBJ/BabylonExport/Entities/Mesh.cs
  57. 69 0
      Exporters/FBX - OBJ/BabylonExport/Entities/PositionNormalTextured.cs
  58. 75 0
      Exporters/FBX - OBJ/BabylonExport/Entities/PositionNormalTexturedWeights.cs
  59. 42 0
      Exporters/FBX - OBJ/BabylonExport/Entities/ProxyMesh.cs
  60. 76 0
      Exporters/FBX - OBJ/BabylonExport/Entities/StandardMaterial.cs
  61. 978 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/Blender/io_export_babylon.py
  62. 298 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/FBXExporter.cs
  63. 194 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/ContentBuilder.cs
  64. 49 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/ErrorLogger.cs
  65. 86 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/GraphicsDeviceService.cs
  66. 30 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/ServiceContainer.cs
  67. 28 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/Microsoft.Xna.GameStudio.ContentPipelineExtensions.targets
  68. 42 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/Microsoft.Xna.GameStudio.targets
  69. 57 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/AnimationClip.cs
  70. 218 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/AnimationPlayer.cs
  71. BIN
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/Background.png
  72. 62 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/Keyframe.cs
  73. 6 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/Properties/AppManifest.xml
  74. 31 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/Properties/AssemblyInfo.cs
  75. 32 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/Properties/WMAppManifest.xml
  76. 194 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/SkinnedModelWindows.csproj
  77. 76 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/SkinningData.cs
  78. 31 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModelPipeline/Properties/AssemblyInfo.cs
  79. 70 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModelPipeline/SkinnedModelPipeline.csproj
  80. 271 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModelPipeline/SkinnedModelProcessor.cs
  81. BIN
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.Framework.Tools.Packaging.Tasks.dll
  82. 24 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.GameStudio.AvailablePlatforms.targets
  83. 286 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.GameStudio.Common.targets
  84. 343 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.GameStudio.Content.targets
  85. 493 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.GameStudio.ContentPipeline.targets
  86. 26 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.GameStudio.Windows.targets
  87. 54 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.GameStudio.Xbox 360.targets
  88. 13 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/IExporter.cs
  89. 431 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/MXB/NovaExporter.Materials.cs
  90. 630 0
      Exporters/FBX - OBJ/BabylonExport/Exporters/MXB/NovaExporter.cs
  91. 123 0
      Exporters/FBX - OBJ/BabylonExport/Program.cs
  92. BIN
      Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.AudioImporters.dll
  93. BIN
      Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.EffectImporter.dll
  94. BIN
      Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.FBXImporter.dll
  95. BIN
      Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.TextureImporter.dll
  96. BIN
      Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.VideoImporters.dll
  97. BIN
      Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.XImporter.dll
  98. BIN
      Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.dll
  99. BIN
      Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Tools.Packaging.Tasks.dll
  100. 0 0
      Exporters/FBX - OBJ/BabylonExport/Refs/SharpDX.DXGI.dll

+ 6 - 8
Babylon/Animations/babylon.animatable.js

@@ -6,7 +6,6 @@
         this.fromFrame = from;
         this.toFrame = to;
         this.loopAnimation = loop;
-        this.animationStartDate = new Date();
         this.speedRatio = speedRatio ? speedRatio : 1.0;
     };
     
@@ -19,18 +18,17 @@
     BABYLON._Animatable.prototype.speedRatio = 1.0;
     
     // Methods
-    BABYLON._Animatable.prototype._animate = function () {
-
-        // Getting time
-        var now = new Date();
-        var delay = now - this.animationStartDate;
+    BABYLON._Animatable.prototype._animate = function (delay) {
+        if (!this._localDelayOffset) {
+            this._localDelayOffset = delay;
+        }
 
         // Animating
         var running = false;
         var animations = this.target.animations;
         for (var index = 0; index < animations.length; index++) {
-            var isRunning = animations[index].animate(this.target, delay, this.fromFrame, this.toFrame, this.loopAnimation, this.speedRatio);
-            running = running || isRunning;
+            var isRunning = animations[index].animate(this.target, delay - this._localDelayOffset, this.fromFrame, this.toFrame, this.loopAnimation, this.speedRatio);
+            running = running || isRunning;            
         }
 
         return running;

+ 16 - 2
Babylon/Animations/babylon.animation.js

@@ -34,7 +34,7 @@
         if (loopMode === BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT && repeatCount > 0) {
             return highLimitValue.clone ? highLimitValue.clone() : highLimitValue;
         }
-
+        
         for (var key = 0; key < this._keys.length; key++) {
             if (this._keys[key + 1].frame >= currentFrame) {
                 var startValue = this._keys[key].value;
@@ -65,7 +65,7 @@
                                 break;
                         }
 
-                        return quaternion.toEulerAngles();
+                        return quaternion;
                     // Vector3
                     case BABYLON.Animation.ANIMATIONTYPE_VECTOR3:
                         switch (loopMode) {
@@ -75,6 +75,14 @@
                             case BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE:
                                 return BABYLON.Vector3.Lerp(startValue, endValue, gradient).add(offsetValue.scale(repeatCount));
                         }
+                    // Matrix
+                    case BABYLON.Animation.ANIMATIONTYPE_MATRIX:
+                        switch (loopMode) {
+                            case BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE:
+                            case BABYLON.Animation.ANIMATIONLOOPMODE_CONSTANT:
+                            case BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE:
+                                return startValue;
+                        }
                     default:
                         break;
                 }
@@ -163,6 +171,11 @@
         } else {
             target[this.targetPropertyPath[0]] = currentValue;
         }
+        
+        if (target.markAsDirty) {
+            target.markAsDirty();
+        }
+
         return true;
     };
 
@@ -170,6 +183,7 @@
     BABYLON.Animation.ANIMATIONTYPE_FLOAT = 0;
     BABYLON.Animation.ANIMATIONTYPE_VECTOR3 = 1;
     BABYLON.Animation.ANIMATIONTYPE_QUATERNION = 2;
+    BABYLON.Animation.ANIMATIONTYPE_MATRIX = 3;
 
     BABYLON.Animation.ANIMATIONLOOPMODE_RELATIVE = 0;
     BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE = 1;

+ 73 - 0
Babylon/Bones/babylon.bone.js

@@ -0,0 +1,73 @@
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.Bone = function (name, skeleton, parentBone, matrix) {
+        this.name = name;
+        this._skeleton = skeleton;
+        this._matrix = matrix;
+        this._baseMatrix = matrix;
+        this._worldTransform = new BABYLON.Matrix();
+        this._absoluteTransform = new BABYLON.Matrix();
+        this._invertedAbsoluteTransform = new BABYLON.Matrix();
+        this.children = [];
+        this.animations = [];
+
+        skeleton.bones.push(this);
+        
+        if (parentBone) {
+            this._parent = parentBone;
+            parentBone.children.push(this);
+        } else {
+            this._parent = null;
+        }
+        
+        this._updateDifferenceMatrix();
+    };
+        
+    // Members
+    BABYLON.Bone.prototype.getParent = function() {
+        return this._parent;
+    };
+    
+    BABYLON.Bone.prototype.getLocalMatrix = function () {
+        return this._matrix;
+    };
+
+    BABYLON.Bone.prototype.getAbsoluteMatrix = function () {
+        var matrix = this._matrix.clone();
+        var parent = this._parent;
+
+        while (parent) {
+            matrix = matrix.multiply(parent.getLocalMatrix());
+            parent = parent.getParent();
+        }
+
+        return matrix;
+    };
+
+    // Methods
+    BABYLON.Bone.prototype.updateMatrix = function(matrix) {
+        this._matrix = matrix;
+        this._skeleton._markAsDirty();
+
+        this._updateDifferenceMatrix();
+    };
+
+    BABYLON.Bone.prototype._updateDifferenceMatrix = function() {
+        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();
+        }
+    };
+
+    BABYLON.Bone.prototype.markAsDirty = function() {
+        this._skeleton._markAsDirty();
+    };
+})();

+ 81 - 0
Babylon/Bones/babylon.skeleton.js

@@ -0,0 +1,81 @@
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.Skeleton = function (name, id, scene) {
+        this.id = id;
+        this.name = name;
+        this.bones = [];
+
+        this._scene = scene;
+
+        scene.skeletons.push(this);
+
+        this._isDirty = true;
+    };
+        
+    // Members
+    BABYLON.Skeleton.prototype.getTransformMatrices = function () {       
+        return this._transformMatrices;
+    };
+
+    // Methods
+    BABYLON.Skeleton.prototype._markAsDirty = function() {
+        this._isDirty = true;
+    };
+
+    BABYLON.Skeleton.prototype.prepare = function() {
+        if (!this._isDirty) {
+            return;
+        }
+
+        if (!this._transformMatrices || this._transformMatrices.length !== 16 * this.bones.length) {
+            this._transformMatrices = new BABYLON.MatrixType(16 * this.bones.length);
+        }
+
+        for (var index = 0; index < this.bones.length; index++) {
+            var bone = this.bones[index];
+            var parentBone = bone.getParent();
+
+            if (parentBone) {
+                bone._matrix.multiplyToRef(parentBone._worldTransform, bone._worldTransform);
+            } else {
+                bone._worldTransform.copyFrom(bone._matrix);
+            }
+
+            bone._invertedAbsoluteTransform.multiplyToArray(bone._worldTransform, this._transformMatrices, index * 16);
+        }
+
+        this._isDirty = false;
+    };
+    
+    BABYLON.Skeleton.prototype.getAnimatables = function () {
+        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;
+    };
+
+    BABYLON.Skeleton.prototype.clone = function(name, id) {
+        var result = new BABYLON.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 BABYLON.Bone(source.name, result, parentBone, source._baseMatrix);
+            BABYLON.Tools.DeepCopy(source.animations, bone.animations);
+        }
+
+        return result;
+    };
+})();

+ 138 - 101
Babylon/Cameras/babylon.arcRotateCamera.js

@@ -47,136 +47,168 @@
     BABYLON.ArcRotateCamera.prototype.upperRadiusLimit = null;
 
     // Methods
-    BABYLON.ArcRotateCamera.prototype.attachControl = function(canvas) {
+    BABYLON.ArcRotateCamera.prototype.attachControl = function(canvas, noPreventDefault) {
         var previousPosition;
         var that = this;
         var pointerId;
+        
+        if (this._attachedCanvas) {
+            return;
+        }
+        this._attachedCanvas = canvas;
 
         var engine = this._scene.getEngine();
-        
-        this._onPointerDown = function (evt) {
-            
-            if (pointerId) {
-                return;
-            }
 
-            pointerId = evt.pointerId;
+        if (this._onPointerDown === undefined) {
+            this._onPointerDown = function(evt) {
+
+                if (pointerId) {
+                    return;
+                }
+
+                pointerId = evt.pointerId;
+
+                previousPosition = {
+                    x: evt.clientX,
+                    y: evt.clientY
+                };
 
-            previousPosition = {
-                x: evt.clientX,
-                y: evt.clientY
+                if (!noPreventDefault) {
+                    evt.preventDefault();
+                }
             };
 
-            evt.preventDefault();
-        };
+            this._onPointerUp = function(evt) {
+                previousPosition = null;
+                pointerId = null;
+                if (!noPreventDefault) {
+                    evt.preventDefault();
+                }
+            };
 
-        this._onPointerUp = function (evt) {
-            previousPosition = null;
-            pointerId = null;
-            evt.preventDefault();
-        };
+            this._onPointerMove = function(evt) {
+                if (!previousPosition) {
+                    return;
+                }
 
-        this._onPointerMove = function (evt) {
-            if (!previousPosition) {
-                return;
-            }
-            
-            if (pointerId !== evt.pointerId) {
-                return;
-            }
+                if (pointerId !== evt.pointerId) {
+                    return;
+                }
 
-            var offsetX = evt.clientX - previousPosition.x;
-            var offsetY = evt.clientY - previousPosition.y;
+                var offsetX = evt.clientX - previousPosition.x;
+                var offsetY = evt.clientY - previousPosition.y;
 
-            that.inertialAlphaOffset -= offsetX / 1000;
-            that.inertialBetaOffset -= offsetY / 1000;
+                that.inertialAlphaOffset -= offsetX / 1000;
+                that.inertialBetaOffset -= offsetY / 1000;
 
-            previousPosition = {
-                x: evt.clientX,
-                y: evt.clientY
+                previousPosition = {
+                    x: evt.clientX,
+                    y: evt.clientY
+                };
+
+                if (!noPreventDefault) {
+                    evt.preventDefault();
+                }
             };
 
-            evt.preventDefault();
-        };
-        
-        this._onMouseMove = function (evt) {
-            if (!engine.isPointerLock) {
-                return;
-            }
+            this._onMouseMove = function(evt) {
+                if (!engine.isPointerLock) {
+                    return;
+                }
 
-            var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
-            var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
+                var offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
+                var offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
 
-            that.inertialAlphaOffset -= offsetX / 1000;
-            that.inertialBetaOffset -= offsetY / 1000;
+                that.inertialAlphaOffset -= offsetX / 1000;
+                that.inertialBetaOffset -= offsetY / 1000;
 
-            evt.preventDefault();
-        };
+                if (!noPreventDefault) {
+                    evt.preventDefault();
+                }
+            };
 
-        this._wheel = function(event) {
-            var delta = 0;
-            if (event.wheelDelta) {
-                delta = event.wheelDelta / 120;
-            } else if (event.detail) {
-                delta = -event.detail / 3;
-            }
+            this._wheel = function(event) {
+                var delta = 0;
+                if (event.wheelDelta) {
+                    delta = event.wheelDelta / 120;
+                } else if (event.detail) {
+                    delta = -event.detail / 3;
+                }
 
-            if (delta)
-                that.radius -= delta;
+                if (delta)
+                    that.radius -= delta;
 
-            if (event.preventDefault)
-                event.preventDefault();
-        };
-        
-        this._onKeyDown = function (evt) {
-            if (that.keysUp.indexOf(evt.keyCode) !== -1 ||
-                that.keysDown.indexOf(evt.keyCode) !== -1 ||
-                that.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                that.keysRight.indexOf(evt.keyCode) !== -1) {
-                var index = that._keys.indexOf(evt.keyCode);
-
-                if (index === -1) {
-                    that._keys.push(evt.keyCode);
+                if (event.preventDefault) {
+                    if (!noPreventDefault) {
+                        event.preventDefault();
+                    }
                 }
-                evt.preventDefault();
-            }
-        };
+            };
 
-        this._onKeyUp = function (evt) {
-            if (that.keysUp.indexOf(evt.keyCode) !== -1 ||
-                that.keysDown.indexOf(evt.keyCode) !== -1 ||
-                that.keysLeft.indexOf(evt.keyCode) !== -1 ||
-                that.keysRight.indexOf(evt.keyCode) !== -1) {
-                var index = that._keys.indexOf(evt.keyCode);
+            this._onKeyDown = function(evt) {
+                if (that.keysUp.indexOf(evt.keyCode) !== -1 ||
+                    that.keysDown.indexOf(evt.keyCode) !== -1 ||
+                    that.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                    that.keysRight.indexOf(evt.keyCode) !== -1) {
+                    var index = that._keys.indexOf(evt.keyCode);
+
+                    if (index === -1) {
+                        that._keys.push(evt.keyCode);
+                    }
+
+                    if (evt.preventDefault) {
+                        if (!noPreventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
+                }
+            };
 
-                if (index >= 0) {
-                    that._keys.splice(index, 1);
+            this._onKeyUp = function(evt) {
+                if (that.keysUp.indexOf(evt.keyCode) !== -1 ||
+                    that.keysDown.indexOf(evt.keyCode) !== -1 ||
+                    that.keysLeft.indexOf(evt.keyCode) !== -1 ||
+                    that.keysRight.indexOf(evt.keyCode) !== -1) {
+                    var index = that._keys.indexOf(evt.keyCode);
+
+                    if (index >= 0) {
+                        that._keys.splice(index, 1);
+                    }
+
+                    if (evt.preventDefault) {
+                        if (!noPreventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
+                }
+            };
+
+            this._onLostFocus = function() {
+                that._keys = [];
+                pointerId = null;
+            };
+
+            this._onGestureStart = function(e) {
+                if (!that._MSGestureHandler) {
+                    that._MSGestureHandler = new MSGesture();
+                    that._MSGestureHandler.target = canvas;
                 }
-                evt.preventDefault();
-            }
-        };
-        
-        this._onLostFocus = function () {
-            that._keys = [];
-            pointerId = null;
-        };
-
-        this._onGestureStart = function (e) {
-            if (!that._MSGestureHandler) {
-                that._MSGestureHandler = new MSGesture();
-                that._MSGestureHandler.target = canvas;
-            }
 
-            that._MSGestureHandler.addPointer(e.pointerId);
-        };
+                that._MSGestureHandler.addPointer(e.pointerId);
+            };
 
-        this._onGesture = function(e) {
-            that.radius *= e.scale;
+            this._onGesture = function(e) {
+                that.radius *= e.scale;
+
+                if (e.preventDefault) {
+                    if (!noPreventDefault) {
+                        e.stopPropagation();
+                        e.preventDefault();
+                    }
+                }
+            };
+        }
 
-            e.preventDefault();
-            e.stopPropagation();
-        };
-        
         canvas.addEventListener(eventPrefix + "down", this._onPointerDown);
         canvas.addEventListener(eventPrefix + "up", this._onPointerUp);
         canvas.addEventListener(eventPrefix + "out", this._onPointerUp);
@@ -191,6 +223,10 @@
     };
     
     BABYLON.ArcRotateCamera.prototype.detachControl = function (canvas) {
+        if (this._attachedCanvas != canvas) {
+            return;
+        }
+
         canvas.removeEventListener(eventPrefix + "down", this._onPointerDown);
         canvas.removeEventListener(eventPrefix + "up", this._onPointerUp);
         canvas.removeEventListener(eventPrefix + "out", this._onPointerUp);
@@ -204,6 +240,7 @@
         window.removeEventListener("blur", this._onLostFocus);
 
         this._MSGestureHandler = null;
+        this._attachedCanvas = null;
     };
 
     BABYLON.ArcRotateCamera.prototype._update = function () {

+ 1 - 1
Babylon/Cameras/babylon.camera.js

@@ -58,7 +58,7 @@
 
         var halfWidth = engine.getRenderWidth() / 2.0;
         var halfHeight = engine.getRenderHeight() / 2.0;
-        BABYLON.Matrix.OrthoOffCenterLHToRef(this.orthoLeft || -halfWidth, this.orthoRight || halfWidth, this.orthoBottom || -halfHeight, this.orthoTop || halfHeight, this.minZ, this.maxZ);
+        BABYLON.Matrix.OrthoOffCenterLHToRef(this.orthoLeft || -halfWidth, this.orthoRight || halfWidth, this.orthoBottom || -halfHeight, this.orthoTop || halfHeight, this.minZ, this.maxZ, this._projectionMatrix);
         return this._projectionMatrix;
     };
 })();

+ 30 - 7
Babylon/Cameras/babylon.freeCamera.js

@@ -83,10 +83,15 @@
     };
 
     // Controls
-    BABYLON.FreeCamera.prototype.attachControl = function (canvas) {
+    BABYLON.FreeCamera.prototype.attachControl = function (canvas, noPreventDefault) {
         var previousPosition;
         var that = this;
         var engine = this._scene.getEngine();
+        
+        if (this._attachedCanvas) {
+            return;
+        }
+        this._attachedCanvas = canvas;
 
         if (this._onMouseDown === undefined) {
             this._onMouseDown = function (evt) {
@@ -95,18 +100,24 @@
                     y: evt.clientY
                 };
 
-                evt.preventDefault();
+                if (!noPreventDefault) {
+                    evt.preventDefault();
+                }
             };
 
             this._onMouseUp = function (evt) {
                 previousPosition = null;
-                evt.preventDefault();
+                if (!noPreventDefault) {
+                    evt.preventDefault();
+                }
             };
 
             this._onMouseOut = function (evt) {
                 previousPosition = null;
                 that._keys = [];
-                evt.preventDefault();
+                if (!noPreventDefault) {
+                    evt.preventDefault();
+                }
             };
 
             this._onMouseMove = function (evt) {
@@ -132,7 +143,9 @@
                     x: evt.clientX,
                     y: evt.clientY
                 };
-                evt.preventDefault();
+                if (!noPreventDefault) {
+                    evt.preventDefault();
+                }
             };
 
             this._onKeyDown = function (evt) {
@@ -145,7 +158,9 @@
                     if (index === -1) {
                         that._keys.push(evt.keyCode);
                     }
-                    evt.preventDefault();
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
                 }
             };
 
@@ -159,7 +174,9 @@
                     if (index >= 0) {
                         that._keys.splice(index, 1);
                     }
-                    evt.preventDefault();
+                    if (!noPreventDefault) {
+                        evt.preventDefault();
+                    }
                 }
             };
 
@@ -178,6 +195,10 @@
     };
 
     BABYLON.FreeCamera.prototype.detachControl = function (canvas) {
+        if (this._attachedCanvas != canvas) {
+            return;
+        }
+
         canvas.removeEventListener("mousedown", this._onMouseDown);
         canvas.removeEventListener("mouseup", this._onMouseUp);
         canvas.removeEventListener("mouseout", this._onMouseOut);
@@ -185,6 +206,8 @@
         window.removeEventListener("keydown", this._onKeyDown);
         window.removeEventListener("keyup", this._onKeyUp);
         window.removeEventListener("blur", this._onLostFocus);
+        
+        this._attachedCanvas = null;
     };
 
     BABYLON.FreeCamera.prototype._collideWithWorld = function (velocity) {

+ 82 - 53
Babylon/Cameras/babylon.touchCamera.js

@@ -33,70 +33,93 @@
         
         // Internals
         this._cameraRotationMatrix = new BABYLON.Matrix();
+        this._referencePoint = BABYLON.Vector3.Zero();
+        this._currentTarget = BABYLON.Vector3.Zero();
+        this._transformedReferencePoint = BABYLON.Vector3.Zero();
+        this._viewMatrix = BABYLON.Matrix.Zero();
+        this._upVector = BABYLON.Vector3.Up();
+        this._oldPosition = BABYLON.Vector3.Zero();
+        this._diffPosition = BABYLON.Vector3.Zero();
+        this._newPosition = BABYLON.Vector3.Zero();
     };
 
     BABYLON.TouchCamera.prototype = Object.create(BABYLON.FreeCamera.prototype);
 
     // Controls
-    BABYLON.TouchCamera.prototype.attachControl = function (canvas) {
+    BABYLON.TouchCamera.prototype.attachControl = function (canvas, noPreventDefault) {
         var previousPosition;
         var that = this;
+        
+        if (this._attachedCanvas) {
+            return;
+        }
+        this._attachedCanvas = canvas;
+
+        if (this._onPointerDown === undefined) {
 
-        this._onPointerDown = function (evt) {
-            evt.preventDefault();
+            this._onPointerDown = function(evt) {
 
-            that._pointerPressed.push(evt.pointerId);
-            
-            if (that._pointerPressed.length !== 1) {
-                return;
-            }
+                if (!noPreventDefault) {
+                    evt.preventDefault();
+                }
 
-            previousPosition = {
-                x: evt.clientX,
-                y: evt.clientY
+                that._pointerPressed.push(evt.pointerId);
+
+                if (that._pointerPressed.length !== 1) {
+                    return;
+                }
+
+                previousPosition = {
+                    x: evt.clientX,
+                    y: evt.clientY
+                };
             };
-        };
-
-        this._onPointerUp = function (evt) {
-            evt.preventDefault();
-            
-            var index = that._pointerPressed.indexOf(evt.pointerId);
-
-            if (index === -1) {
-                return;
-            }
-            that._pointerPressed.splice(index, 1);
-            
-            if (index != 0) {
-                return;
-            }
-            previousPosition = null;
-            that._offsetX = null;
-            that._offsetY = null;
-        };
-
-        this._onPointerMove = function (evt) {
-            evt.preventDefault();
-            
-            if (!previousPosition) {
-                return;
-            }
-            
-            var index = that._pointerPressed.indexOf(evt.pointerId);
-            
-            if (index != 0) {
-                return;
-            }
-
-            that._offsetX = evt.clientX - previousPosition.x;
-            that._offsetY = -(evt.clientY - previousPosition.y);
-        };
-        
-        this._onLostFocus = function () {
-            that._offsetX = null;
-            that._offsetY = null;
-        };
-        
+
+            this._onPointerUp = function(evt) {
+                if (!noPreventDefault) {
+                    evt.preventDefault();
+                }
+
+                var index = that._pointerPressed.indexOf(evt.pointerId);
+
+                if (index === -1) {
+                    return;
+                }
+                that._pointerPressed.splice(index, 1);
+
+                if (index != 0) {
+                    return;
+                }
+                previousPosition = null;
+                that._offsetX = null;
+                that._offsetY = null;
+            };
+
+            this._onPointerMove = function(evt) {
+                if (!noPreventDefault) {
+                    evt.preventDefault();
+                }
+
+                if (!previousPosition) {
+                    return;
+                }
+
+                var index = that._pointerPressed.indexOf(evt.pointerId);
+
+                if (index != 0) {
+                    return;
+                }
+
+                that._offsetX = evt.clientX - previousPosition.x;
+                that._offsetY = -(evt.clientY - previousPosition.y);
+            };
+
+            this._onLostFocus = function() {
+                that._offsetX = null;
+                that._offsetY = null;
+            };
+        }
+
         canvas.addEventListener("pointerdown", this._onPointerDown);
         canvas.addEventListener("pointerup", this._onPointerUp);
         canvas.addEventListener("pointerout", this._onPointerUp);
@@ -105,11 +128,17 @@
     };
 
     BABYLON.TouchCamera.prototype.detachControl = function (canvas) {
+        if (this._attachedCanvas != canvas) {
+            return;
+        }
+
         canvas.removeEventListener("pointerdown", this._onPointerDown);
         canvas.removeEventListener("pointerup", this._onPointerUp);
         canvas.removeEventListener("pointerout", this._onPointerUp);
         canvas.removeEventListener("pointermove", this._onPointerMove);
         window.removeEventListener("blur", this._onLostFocus);
+        
+        this._attachedCanvas = null;
     };
     
     BABYLON.TouchCamera.prototype._checkInputs = function () {

+ 52 - 27
Babylon/Lights/Shadows/babylon.shadowGenerator.js

@@ -11,46 +11,43 @@
         this._shadowMap = new BABYLON.RenderTargetTexture(light.name + "_shadowMap", mapSize, this._scene, false);
         this._shadowMap.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
         this._shadowMap.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
-        
-        // Effect
-        this._effect = this._scene.getEngine().createEffect("shadowMap",
-                    ["position"],
-                    ["worldViewProjection"],
-                    [], "");
-        
-        this._effectVSM = this._scene.getEngine().createEffect("shadowMap",
-                    ["position"],
-                    ["worldViewProjection"],
-                    [], "#define VSM");
-        
+                
         // Custom render function
         var that = this;
 
-        var renderSubMesh = function (subMesh, effect) {
+        var renderSubMesh = function (subMesh) {
             var mesh = subMesh.getMesh();
             var world = mesh.getWorldMatrix();
+            var engine = that._scene.getEngine();
 
-            world.multiplyToRef(that.getTransformMatrix(), that._worldViewProjection);
-            
-            effect.setMatrix("worldViewProjection", that._worldViewProjection);
-            
-            // Bind and draw
-            mesh.bindAndDraw(subMesh, effect, false);
+            if (that.isReady(mesh)) {
+                engine.enableEffect(that._effect);
+                
+                // Bones
+                if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+                    that._effect.setMatrix("world", world);
+                    that._effect.setMatrix("viewProjection", that.getTransformMatrix());
+
+                    that._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
+                } else {
+                    world.multiplyToRef(that.getTransformMatrix(), that._worldViewProjection);
+                    that._effect.setMatrix("worldViewProjection", that._worldViewProjection);
+                }
+
+                // Bind and draw
+                mesh.bindAndDraw(subMesh, that._effect, false);
+            }
         };
 
         this._shadowMap.customRenderFunction = function (opaqueSubMeshes, alphaTestSubMeshes, transparentSubMeshes, activeMeshes) {
-            var engine = that._scene.getEngine();
             var index;
-            var effect = that.useVarianceShadowMap ? that._effectVSM : that._effect;
-
-            engine.enableEffect(effect);
             
             for (index = 0; index < opaqueSubMeshes.length; index++) {
-                renderSubMesh(opaqueSubMeshes.data[index], effect);
+                renderSubMesh(opaqueSubMeshes.data[index]);
             }
             
             for (index = 0; index < alphaTestSubMeshes.length; index++) {
-                renderSubMesh(alphaTestSubMeshes.data[index], effect);
+                renderSubMesh(alphaTestSubMeshes.data[index]);
             }
         };
         
@@ -65,8 +62,36 @@
     BABYLON.ShadowGenerator.prototype.useVarianceShadowMap = true;
     
     // Properties
-    BABYLON.ShadowGenerator.prototype.isReady = function () {
-        return this._effect.isReady() && this._effectVSM.isReady();
+    BABYLON.ShadowGenerator.prototype.isReady = function (mesh) {
+        var defines = [];
+        
+        if (this.useVarianceShadowMap) {
+            defines.push("#define VSM");
+        }
+        
+        if (BABYLON.Tools.isIE()) {
+            defines.push("#define IE");
+        }
+
+        var attribs = [BABYLON.VertexBuffer.PositionKind];
+        if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+            attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
+            attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
+            defines.push("#define BONES");
+            defines.push("#define BonesPerMesh " + mesh.skeleton.bones.length);
+        }
+
+        // Get correct effect      
+        var join = defines.join("\n");
+        if (this._cachedDefines != join) {
+            this._cachedDefines = join;
+            this._effect = this._scene.getEngine().createEffect("shadowMap",
+                attribs,
+                ["world", "mBones", "viewProjection", "worldViewProjection"],
+                [], join);
+        }
+
+        return this._effect.isReady();
     };
     
     BABYLON.ShadowGenerator.prototype.getShadowMap = function () {

+ 4 - 0
Babylon/Materials/babylon.effect.js

@@ -163,6 +163,10 @@
         this._valueCache[uniformName][2] = vector.z;
     };
 
+    BABYLON.Effect.prototype.setMatrices = function (uniformName, matrices) {
+        this._engine.setMatrices(this.getUniform(uniformName), matrices);
+    };
+
     BABYLON.Effect.prototype.setMatrix = function (uniformName, matrix) {
         //if (this._valueCache[uniformName] && this._valueCache[uniformName].equals(matrix))
         //    return;

+ 13 - 0
Babylon/Materials/babylon.multiMaterial.js

@@ -19,4 +19,17 @@
 
         return this.subMaterials[index];
     };
+    
+    // Methods
+    BABYLON.MultiMaterial.prototype.isReady = function (mesh) {
+        var result = true;
+        for (var index = 0; index < this.subMaterials.length; index++) {
+            var subMaterial = this.subMaterials[index];
+            if (subMaterial) {
+                result &= this.subMaterials[index].isReady(mesh);
+            }
+        }
+
+        return result;
+    };
 })();

+ 69 - 17
Babylon/Materials/babylon.standardMaterial.js

@@ -1,11 +1,6 @@
 var BABYLON = BABYLON || {};
 
 (function () {
-
-    var isIE = function () {
-        return window.ActiveXObject !== undefined;
-    };
-
     BABYLON.StandardMaterial = function (name, scene) {
         this.name = name;
         this.id = name;
@@ -52,7 +47,7 @@
     };
 
     // Methods   
-    BABYLON.StandardMaterial.prototype.isReady = function (mesh) {        
+    BABYLON.StandardMaterial.prototype.isReady = function (mesh) {
         if (!this.checkReadyOnEveryCall) {
             if (this._renderId === this._scene.getRenderId()) {
                 return true;
@@ -155,7 +150,7 @@
 
             // Shadows
             var shadowGenerator = light.getShadowGenerator();
-            if (mesh && mesh.receiveShadows && shadowGenerator && shadowGenerator.isReady()) {
+            if (mesh && mesh.receiveShadows && shadowGenerator) {
                 defines.push("#define SHADOW" + lightIndex);
 
                 if (!shadowsActivated) {
@@ -173,20 +168,26 @@
                 break;
         }
 
-        var attribs = ["position", "normal"];
+        var attribs = [BABYLON.VertexBuffer.PositionKind, BABYLON.VertexBuffer.NormalKind];
         if (mesh) {
             if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
-                attribs.push("uv");
+                attribs.push(BABYLON.VertexBuffer.UVKind);
                 defines.push("#define UV1");
             }
             if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
-                attribs.push("uv2");
+                attribs.push(BABYLON.VertexBuffer.UV2Kind);
                 defines.push("#define UV2");
             }
             if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
-                attribs.push("color");
+                attribs.push(BABYLON.VertexBuffer.ColorKind);
                 defines.push("#define VERTEXCOLOR");
             }
+            if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+                attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
+                attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
+                defines.push("#define BONES");
+                defines.push("#define BonesPerMesh " + mesh.skeleton.bones.length);
+            }
         }
 
         // Get correct effect      
@@ -196,19 +197,20 @@
 
             // IE patch
             var shaderName = "default";
-            if (isIE()) {
+            if (BABYLON.Tools.isIE()) {
                 shaderName = "iedefault";
             }
 
             this._effect = this._scene.getEngine().createEffect(shaderName,
                 attribs,
-            ["world", "view", "worldViewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vDiffuseColor", "vSpecularColor", "vEmissiveColor",
+                ["world", "view", "worldViewProjection", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vDiffuseColor", "vSpecularColor", "vEmissiveColor",
                 "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",
                  "vDiffuseInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vSpecularInfos", "vBumpInfos",
+                 "mBones",
                  "vClipPlane", "diffuseMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "specularMatrix", "bumpMatrix"],
                 ["diffuseSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "specularSampler", "bumpSampler",
                  "shadowSampler0", "shadowSampler1", "shadowSampler2", "shadowSampler3"
@@ -243,9 +245,17 @@
         this._baseColor.copyFrom(this.diffuseColor);
 
         // Matrices        
-        world.multiplyToRef(this._scene.getTransformMatrix(), this._worldViewProjectionMatrix);
         this._effect.setMatrix("world", world);
-        this._effect.setMatrix("worldViewProjection", this._worldViewProjectionMatrix);
+
+        // Bones
+        if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+            this._effect.setMatrix("viewProjection", this._scene.getTransformMatrix());
+
+            this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
+        } else {
+            world.multiplyToRef(this._scene.getTransformMatrix(), this._worldViewProjectionMatrix);
+            this._effect.setMatrix("worldViewProjection", this._worldViewProjectionMatrix);
+        }
 
         // Textures        
         if (this.diffuseTexture) {
@@ -345,7 +355,7 @@
 
             // Shadows
             var shadowGenerator = light.getShadowGenerator();
-            if (mesh.receiveShadows && shadowGenerator && shadowGenerator.isReady()) {
+            if (mesh.receiveShadows && shadowGenerator) {
                 world.multiplyToRef(shadowGenerator.getTransformMatrix(), this._lightMatrix);
                 this._effect.setMatrix("lightMatrix" + lightIndex, this._lightMatrix);
                 this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMap());
@@ -370,7 +380,7 @@
         if (this._scene.fogMode !== BABYLON.Scene.FOGMODE_NONE) {
             this._effect.setFloat4("vFogInfos", this._scene.fogMode, this._scene.fogStart, this._scene.fogEnd, this._scene.fogDensity);
             this._effect.setColor3("vFogColor", this._scene.fogColor);
-        }        
+        }
     };
 
     BABYLON.StandardMaterial.prototype.getAnimatables = function () {
@@ -438,4 +448,46 @@
 
         this.baseDispose();
     };
+
+    BABYLON.StandardMaterial.prototype.clone = function (name) {
+        var newStandardMaterial = new BABYLON.StandardMaterial(name, this._scene);
+
+        // Base material
+        newStandardMaterial.checkReadyOnEveryCall = this.checkReadyOnEveryCall;
+        newStandardMaterial.alpha = this.alpha;
+        newStandardMaterial.wireframe = this.wireframe;
+        newStandardMaterial.backFaceCulling = this.backFaceCulling;
+
+        // Standard material
+        if (this.diffuseTexture && this.diffuseTexture.clone) {
+            newStandardMaterial.diffuseTexture = this.diffuseTexture.clone();
+        }
+        if (this.ambientTexture && this.ambientTexture.clone) {
+            newStandardMaterial.ambientTexture = this.ambientTexture.clone();
+        }
+        if (this.opacityTexture && this.opacityTexture.clone) {
+            newStandardMaterial.opacityTexture = this.opacityTexture.clone();
+        }
+        if (this.reflectionTexture && this.reflectionTexture.clone) {
+            newStandardMaterial.reflectionTexture = this.reflectionTexture.clone();
+        }
+        if (this.emissiveTexture && this.emissiveTexture.clone) {
+            newStandardMaterial.emissiveTexture = this.emissiveTexture.clone();
+        }
+        if (this.specularTexture && this.specularTexture.clone) {
+            newStandardMaterial.specularTexture = this.specularTexture.clone();
+        }
+        if (this.bumpTexture && this.bumpTexture.clone) {
+            newStandardMaterial.bumpTexture = this.bumpTexture.clone();
+        }
+
+        newStandardMaterial.ambientColor = this.ambientColor.clone();
+        newStandardMaterial.diffuseColor = this.diffuseColor.clone();
+        newStandardMaterial.specularColor = this.specularColor.clone();
+        newStandardMaterial.specularPower = this.specularPower;
+        newStandardMaterial.emissiveColor = this.emissiveColor.clone();
+
+        return newStandardMaterial;
+    };
+
 })();

+ 1 - 1
Babylon/Materials/textures/babylon.baseTexture.js

@@ -61,7 +61,7 @@
     };
 
     BABYLON.BaseTexture.prototype.releaseInternalTexture = function() {
-        if (this._texture === undefined || this._texture === null) {
+        if (!this._texture) {
             return;
         }
         var texturesCache = this._scene.getEngine().getLoadedTexturesCache();

+ 2 - 2
Babylon/Materials/textures/babylon.cubeTexture.js

@@ -22,7 +22,7 @@
 
     BABYLON.CubeTexture.prototype = Object.create(BABYLON.BaseTexture.prototype);
 
-    BABYLON.CubeTexture.prototype._computeReflectionTextureMatrix = function () {
+    BABYLON.CubeTexture.prototype._computeReflectionTextureMatrix = function() {
         return this._textureMatrix;
-    }
+    };
 })();

+ 17 - 0
Babylon/Materials/textures/babylon.dynamicTexture.js

@@ -10,6 +10,8 @@
         this.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
         this.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
 
+        this._generateMipMaps = generateMipMaps;
+
         this._texture = scene.getEngine().createDynamicTexture(size, generateMipMaps);
         var textureSize = this.getSize();
 
@@ -48,4 +50,19 @@
 
         this.update(invertY);
     };
+    
+    BABYLON.DynamicTexture.prototype.clone = function () {
+        var textureSize = this.getSize();
+        var newTexture = new BABYLON.DynamicTexture(this.name, textureSize.width, this._scene, this._generateMipMaps);
+
+        // Base texture
+        newTexture.hasAlpha = this.hasAlpha;
+        newTexture.level = this.level;
+
+        // Dynamic Texture
+        newTexture.wrapU = this.wrapU;
+        newTexture.wrapV = this.wrapV;
+
+        return newTexture;
+    };
 })();

+ 17 - 1
Babylon/Materials/textures/babylon.mirrorTexture.js

@@ -5,7 +5,8 @@
         this._scene = scene;
         this._scene.textures.push(this);
 
-        this.name = name;        
+        this.name = name;
+        this._generateMipMaps = generateMipMaps;
 
         this._texture = scene.getEngine().createRenderTargetTexture(size, generateMipMaps);
         
@@ -46,4 +47,19 @@
 
         delete BABYLON.clipPlane;
     };
+    
+    BABYLON.MirrorTexture.prototype.clone = function () {
+        var textureSize = this.getSize();
+        var newTexture = new BABYLON.DynamicTexture(this.name, textureSize.width, this._scene, this._generateMipMaps);
+
+        // Base texture
+        newTexture.hasAlpha = this.hasAlpha;
+        newTexture.level = this.level;
+
+        // Mirror Texture
+        newTexture.mirrorPlane = this.mirrorPlane.clone();
+        newTexture.renderList = this.renderList.slice(0);
+
+        return newTexture;
+    };
 })();

+ 16 - 1
Babylon/Materials/textures/babylon.renderTargetTexture.js

@@ -15,7 +15,7 @@
 
     BABYLON.RenderTargetTexture.prototype = Object.create(BABYLON.Texture.prototype);
 
-    // Members    
+    // Members        
     BABYLON.RenderTargetTexture.prototype.isRenderTarget = true;
     BABYLON.RenderTargetTexture.prototype.coordinatesMode = BABYLON.Texture.PROJECTION_MODE;
 
@@ -103,5 +103,20 @@
             this.onAfterRender();
         }
     };
+    
+    BABYLON.RenderTargetTexture.prototype.clone = function () {
+        var textureSize = this.getSize();
+        var newTexture = new BABYLON.DynamicTexture(this.name, textureSize.width, this._scene, this._generateMipMaps);
+
+        // Base texture
+        newTexture.hasAlpha = this.hasAlpha;
+        newTexture.level = this.level;
+
+        // RenderTarget Texture
+        newTexture.coordinatesMode = this.coordinatesMode;
+        newTexture.renderList = this.renderList.slice(0);
+
+        return newTexture;
+    };
 
 })();

+ 25 - 0
Babylon/Materials/textures/babylon.texture.js

@@ -6,6 +6,8 @@
         this._scene.textures.push(this);
 
         this.name = url;
+        this._noMipmap = noMipmap;
+        this._invertY = invertY;
 
         this._texture = this._getFromCache(url, noMipmap);
 
@@ -154,4 +156,27 @@
         }
         return this._cachedTextureMatrix;
     };
+
+    BABYLON.Texture.prototype.clone = function() {
+        var newTexture = new BABYLON.Texture(this._texture.url, this._scene, this._noMipmap, this._invertY);
+
+        // Base texture
+        newTexture.hasAlpha = this.hasAlpha;
+        newTexture.level = this.level;
+
+        // Texture
+        newTexture.uOffset = this.uOffset;
+        newTexture.vOffset = this.vOffset;
+        newTexture.uScale = this.uScale;
+        newTexture.vScale = this.vScale;
+        newTexture.uAng = this.uAng;
+        newTexture.vAng = this.vAng;
+        newTexture.wAng = this.wAng;
+        newTexture.wrapU = this.wrapU;
+        newTexture.wrapV = this.wrapV;
+        newTexture.coordinatesIndex = this.coordinatesIndex;
+        newTexture.coordinatesMode = this.coordinatesMode;
+
+        return newTexture;
+    };
 })();

+ 3 - 3
Babylon/Materials/textures/babylon.videoTexture.js

@@ -18,19 +18,19 @@
         this.video.height = textureSize.height;
         this.video.autoplay = true;
         this.video.loop = true;
-        
+        this.video.preload = true;
+
         var that = this;
         this.video.addEventListener("canplaythrough", function () {
             that._texture.isReady = true;
         });
 
-        this.video.preload = true;
         urls.forEach(function (url) {
             var source = document.createElement("source");
             source.src = url;
             that.video.appendChild(source);
         });
-       
+
         this._lastUpdate = new Date();
     };
 

+ 117 - 32
Babylon/Mesh/babylon.mesh.js

@@ -15,6 +15,8 @@
         this.rotation = new BABYLON.Vector3(0, 0, 0);
         this.scaling = new BABYLON.Vector3(1, 1, 1);
 
+        this._pivotMatrix = BABYLON.Matrix.Identity();
+
         this._indices = [];
         this.subMeshes = [];
 
@@ -26,9 +28,11 @@
         // Cache
         this._positions = null;
         this._cache = {
+            localMatrixUpdated: false,
             position: BABYLON.Vector3.Zero(),
             scaling: BABYLON.Vector3.Zero(),
-            rotation: BABYLON.Vector3.Zero()
+            rotation: BABYLON.Vector3.Zero(),
+            rotationQuaternion: new BABYLON.Quaternion(0, 0, 0, 0)
         };
 
         this._childrenFlag = false;
@@ -36,9 +40,11 @@
         this._localRotation = BABYLON.Matrix.Zero();
         this._localTranslation = BABYLON.Matrix.Zero();
         this._localBillboard = BABYLON.Matrix.Zero();
-        this._localScalingRotation = BABYLON.Matrix.Zero();
+        this._localPivotScaling = BABYLON.Matrix.Zero();
+        this._localPivotScalingRotation = BABYLON.Matrix.Zero();
         this._localWorld = BABYLON.Matrix.Zero();
         this._worldMatrix = BABYLON.Matrix.Zero();
+        this._rotateYByPI = BABYLON.Matrix.RotationY(Math.PI);
 
         this._collisionsTransformMatrix = BABYLON.Matrix.Zero();
         this._collisionsScalingMatrix = BABYLON.Matrix.Zero();
@@ -66,6 +72,8 @@
     BABYLON.Mesh.prototype._isDisposed = false;
     BABYLON.Mesh.prototype.onDispose = null;
 
+    BABYLON.Mesh.prototype.skeleton = null;
+
     // Properties
 
     BABYLON.Mesh.prototype.getBoundingInfo = function () {
@@ -108,19 +116,33 @@
         return this._childrenFlag;
     };
 
+    BABYLON.Mesh.prototype.setPivotMatrix = function (matrix) {
+        this._pivotMatrix = matrix;
+        this._cache.pivotMatrixUpdated = true;
+    };
+
+    BABYLON.Mesh.prototype.getPivotMatrix = function () {
+        return this._localMatrix;
+    };
+
     BABYLON.Mesh.prototype.isSynchronized = function () {
         if (this.billboardMode !== BABYLON.Mesh.BILLBOARDMODE_NONE)
             return false;
 
-        if (!this._cache.position || !this._cache.rotation || !this._cache.scaling) {
+        if (this._cache.pivotMatrixUpdated) {
             return false;
         }
 
         if (!this._cache.position.equals(this.position))
             return false;
 
-        if (!this._cache.rotation.equals(this.rotation))
-            return false;
+        if (this.rotation instanceof BABYLON.Quaternion) {
+            if (!this._cache.rotationQuaternion.equals(this.rotation))
+                return false;
+        } else {
+            if (!this._cache.rotation.equals(this.rotation))
+                return false;
+        }
 
         if (!this._cache.scaling.equals(this.scaling))
             return false;
@@ -167,16 +189,29 @@
 
         this._childrenFlag = true;
         this._cache.position.copyFrom(this.position);
-        this._cache.rotation.copyFrom(this.rotation);
         this._cache.scaling.copyFrom(this.scaling);
+        this._cache.pivotMatrixUpdated = false;
 
+        // Scaling
         BABYLON.Matrix.ScalingToRef(this.scaling.x, this.scaling.y, this.scaling.z, this._localScaling);
-        BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._localRotation);
 
-        this._localScaling.multiplyToRef(this._localRotation, this._localScalingRotation);
+        // Rotation
+        if (this.rotation instanceof BABYLON.Quaternion) {
+            this.rotation.toRotationMatrix(this._localRotation);
+            this._cache.rotationQuaternion.copyFrom(this.rotation);
+        } else {
+            BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._localRotation);
+            this._cache.rotation.copyFrom(this.rotation);
+        }
+
+        // Translation
+        BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._localTranslation);
+
+        // Composing transformations
+        this._pivotMatrix.multiplyToRef(this._localScaling, this._localPivotScaling);
+        this._localPivotScaling.multiplyToRef(this._localRotation, this._localPivotScalingRotation);
 
         // Billboarding
-        BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._localTranslation);
         if (this.billboardMode !== BABYLON.Mesh.BILLBOARDMODE_NONE) {
             var localPosition = this.position.clone();
             var zero = this._scene.activeCamera.position.clone();
@@ -202,18 +237,18 @@
 
             this._localBillboard.invert();
 
-            this._localScalingRotation.multiplyToRef(this._localBillboard, this._localWorld);
-            BABYLON.Matrix.RotationY(Math.PI).multiplyToRef(this._localWorld, this._localScalingRotation);
+            this._localPivotScalingRotation.multiplyToRef(this._localBillboard, this._localWorld);
+            this._rotateYByPI.multiplyToRef(this._localWorld, this._localPivotScalingRotation);
         }
 
         // Parent
         if (this.parent && this.billboardMode === BABYLON.Mesh.BILLBOARDMODE_NONE) {
-            this._localScalingRotation.multiplyToRef(this._localTranslation, this._localWorld);
+            this._localPivotScalingRotation.multiplyToRef(this._localTranslation, this._localWorld);
             var parentWorld = this.parent.getWorldMatrix();
 
             this._localWorld.multiplyToRef(parentWorld, this._worldMatrix);
         } else {
-            this._localScalingRotation.multiplyToRef(this._localTranslation, this._worldMatrix);
+            this._localPivotScalingRotation.multiplyToRef(this._localTranslation, this._worldMatrix);
         }
 
         // Bounding info
@@ -440,6 +475,36 @@
         return results;
     };
 
+    // Geometry
+    BABYLON.Mesh.prototype.applyTransform = function (transform) {
+        // Position
+        if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.PositionKind)) {
+            return;
+        }
+
+        this._resetPointsArrayCache();
+
+        var data = this._vertexBuffers[BABYLON.VertexBuffer.PositionKind].getData();
+        var temp = new BABYLON.MatrixType(data.length);
+        for (var index = 0; index < data.length; index += 3) {
+            BABYLON.Vector3.TransformCoordinates(BABYLON.Vector3.FromArray(data, index), transform).toArray(temp, index);
+        }
+
+        this.setVerticesData(temp, BABYLON.VertexBuffer.PositionKind, this._vertexBuffers[BABYLON.VertexBuffer.PositionKind].isUpdatable());
+
+        // Normals
+        if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
+            return;
+        }
+
+        data = this._vertexBuffers[BABYLON.VertexBuffer.NormalKind].getData();
+        for (var index = 0; index < data.length; index += 3) {
+            BABYLON.Vector3.TransformNormal(BABYLON.Vector3.FromArray(data, index), transform).toArray(temp, index);
+        }
+
+        this.setVerticesData(temp, BABYLON.VertexBuffer.NormalKind, this._vertexBuffers[BABYLON.VertexBuffer.NormalKind].isUpdatable());
+    };
+
     // Cache
     BABYLON.Mesh.prototype._resetPointsArrayCache = function () {
         this._positions = null;
@@ -540,8 +605,20 @@
             }
         }
 
-        if (distance >= 0)
-            return { hit: true, distance: distance };
+        if (distance >= 0) {
+            // Get picked point
+            var world = this.getWorldMatrix();
+            var worldOrigin = BABYLON.Vector3.TransformCoordinates(ray.origin, world);
+            var direction = ray.direction.clone();
+            direction.normalize();
+            direction = direction.scale(distance);
+            var worldDirection = BABYLON.Vector3.TransformNormal(direction, world);
+
+            var pickedPoint = worldOrigin.add(worldDirection);
+
+            // Return result
+            return { hit: true, distance: BABYLON.Vector3.Distance(worldOrigin, pickedPoint), pickedPoint: pickedPoint };
+        }
 
         return { hit: false, distance: 0 };
     };
@@ -560,7 +637,7 @@
         this._indexBuffer.references++;
 
         // Deep copy
-        BABYLON.Tools.DeepCopy(this, result, ["name", "material"], ["_indices", "_totalVertices"]);
+        BABYLON.Tools.DeepCopy(this, result, ["name", "material", "skeleton"], ["_indices", "_totalVertices"]);
 
         // Bounding info
         result._boundingInfo = new BABYLON.BoundingInfo(this.getVerticesData(BABYLON.VertexBuffer.PositionKind), 0, this._totalVertices);
@@ -599,7 +676,9 @@
     // Dispose
     BABYLON.Mesh.prototype.dispose = function (doNotRecurse) {
         if (this._vertexBuffers) {
-            //this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
+            for (var index = 0; index < this._vertexBuffers.length; index++) {
+                this._vertexBuffers[index].dispose();
+            }
             this._vertexBuffers = null;
         }
 
@@ -762,15 +841,15 @@
     };
 
     // Cylinder (Code from SharpDX.org)
-    BABYLON.Mesh.CreateCylinder = function (name, height, diameter, tessellation, scene, updatable) {
-        var radius = diameter / 2;
+    BABYLON.Mesh.CreateCylinder = function (name, height, diameterTop, diameterBottom, tessellation, scene, updatable) {
+        var radiusTop = diameterTop / 2;
+        var radiusBottom = diameterBottom / 2;
         var indices = [];
         var positions = [];
         var normals = [];
         var uvs = [];
         var cylinder = new BABYLON.Mesh(name, scene);
 
-
         var getCircleVector = function (i) {
             var angle = (i * 2.0 * Math.PI / tessellation);
             var dx = Math.sin(angle);
@@ -780,12 +859,18 @@
         };
 
         var createCylinderCap = function (isTop) {
+            var radius = isTop ? radiusTop : radiusBottom;
+            
+            if (radius == 0) {
+                return
+            }
+
             // Create cap indices.
             for (var i = 0; i < tessellation - 2; i++) {
                 var i1 = (i + 1) % tessellation;
                 var i2 = (i + 2) % tessellation;
 
-                if (isTop) {
+                if (!isTop) {
                     var tmp = i1;
                     var i1 = i2;
                     i2 = tmp;
@@ -799,7 +884,7 @@
 
 
             // Which end of the cylinder is this?
-            var normal = new BABYLON.Vector3(0, 1, 0);
+            var normal = new BABYLON.Vector3(0, -1, 0);
             var textureScale = new BABYLON.Vector2(-0.5, -0.5);
 
             if (!isTop) {
@@ -828,16 +913,16 @@
         // Create a ring of triangles around the outside of the cylinder.
         for (var i = 0; i <= tessellation; i++) {
             var normal = getCircleVector(i);
-            var sideOffset = normal.scale(radius);
+            var sideOffsetBottom = normal.scale(radiusBottom);
+            var sideOffsetTop = normal.scale(radiusTop);
             var textureCoordinate = new BABYLON.Vector2(i / tessellation, 0);
 
-            var position = sideOffset.add(topOffset);
+            var position = sideOffsetBottom.add(topOffset);
             positions.push(position.x, position.y, position.z);
             normals.push(normal.x, normal.y, normal.z);
             uvs.push(textureCoordinate.x, textureCoordinate.y);
 
-
-            position = sideOffset.subtract(topOffset);
+            position = sideOffsetTop.subtract(topOffset);
             textureCoordinate.y += 1;
             positions.push(position.x, position.y, position.z);
             normals.push(normal.x, normal.y, normal.z);
@@ -863,6 +948,8 @@
 
         return cylinder;
     };
+    
+    // Cone
 
     // Torus  (Code from SharpDX.org)
     BABYLON.Mesh.CreateTorus = function (name, diameter, thickness, tessellation, scene, updatable) {
@@ -923,7 +1010,6 @@
         return torus;
     };
 
-
     // Plane
     BABYLON.Mesh.CreatePlane = function (name, size, scene, updatable) {
         var plane = new BABYLON.Mesh(name, scene);
@@ -942,11 +1028,11 @@
         positions.push(halfSize, -halfSize, 0);
         normals.push(0, 0, -1.0);
         uvs.push(1.0, 0.0);
-        
+
         positions.push(halfSize, halfSize, 0);
         normals.push(0, 0, -1.0);
         uvs.push(1.0, 1.0);
-        
+
         positions.push(-halfSize, halfSize, 0);
         normals.push(0, 0, -1.0);
         uvs.push(0.0, 1.0);
@@ -1011,8 +1097,7 @@
     BABYLON.Mesh.CreateGroundFromHeightMap = function (name, url, width, height, subdivisions, minHeight, maxHeight, scene, updatable) {
         var ground = new BABYLON.Mesh(name, scene);
 
-        var img = new Image();
-        img.onload = function () {
+        var onload = function (img) {
             var indices = [];
             var positions = [];
             var normals = [];
@@ -1081,7 +1166,7 @@
             ground._isReady = true;
         };
 
-        img.src = url;
+        BABYLON.Tools.LoadImage(url, onload);
 
         ground._isReady = false;
 

+ 18 - 5
Babylon/Mesh/babylon.vertexBuffer.js

@@ -4,6 +4,7 @@
     BABYLON.VertexBuffer = function (mesh, data, kind, updatable) {
         this._mesh = mesh;
         this._engine = mesh.getScene().getEngine();
+        this._updatable = updatable;
         
         if (updatable) {
             this._buffer = this._engine.createDynamicVertexBuffer(data.length * 4);
@@ -32,10 +33,20 @@
             case BABYLON.VertexBuffer.ColorKind:
                 this._strideSize = 3;
                 break;
+            case BABYLON.VertexBuffer.MatricesIndicesKind:
+                this._strideSize = 4;
+                break;
+            case BABYLON.VertexBuffer.MatricesWeightsKind:
+                this._strideSize = 4;
+                break;
         }
     };
     
     // Properties
+    BABYLON.VertexBuffer.prototype.isUpdatable = function () {
+        return this._updatable;
+    };
+
     BABYLON.VertexBuffer.prototype.getData = function() {
         return this._data;
     };
@@ -59,9 +70,11 @@
     }; 
         
     // Enums
-    BABYLON.VertexBuffer.PositionKind   = "position";
-    BABYLON.VertexBuffer.NormalKind     = "normal";
-    BABYLON.VertexBuffer.UVKind         = "uv";
-    BABYLON.VertexBuffer.UV2Kind        = "uv2";
-    BABYLON.VertexBuffer.ColorKind      = "color";
+    BABYLON.VertexBuffer.PositionKind           = "position";
+    BABYLON.VertexBuffer.NormalKind             = "normal";
+    BABYLON.VertexBuffer.UVKind                 = "uv";
+    BABYLON.VertexBuffer.UV2Kind                = "uv2";
+    BABYLON.VertexBuffer.ColorKind              = "color";
+    BABYLON.VertexBuffer.MatricesIndicesKind    = "matricesIndices";
+    BABYLON.VertexBuffer.MatricesWeightsKind    = "matricesWeights";
 })();

+ 1 - 1
Babylon/Particles/babylon.particleSystem.js

@@ -328,7 +328,7 @@
 
     BABYLON.ParticleSystem.prototype.dispose = function () {
         if (this._vertexBuffer) {
-            //this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
+            this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
             this._vertexBuffer = null;
         }
 

+ 6 - 0
Babylon/PostProcess/babylon.postProcess.js

@@ -0,0 +1,6 @@
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.PostProcess = function () {
+    }; 
+})();

+ 20 - 0
Babylon/PostProcess/babylon.postProcessManager.js

@@ -0,0 +1,20 @@
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.PostProcessManager = function () {
+        this.postProcesses = [];
+    };
+
+    // Methods
+    BABYLON.PostProcessManager.prototype._prepareFrame = function () {
+        if (this.postProcesses.length === 0) {
+            return;
+        }
+    };
+    
+    BABYLON.PostProcessManager.prototype._finalizeFrame = function () {
+        if (this.postProcesses.length === 0) {
+            return;
+        }
+    };
+})();

+ 26 - 3
Babylon/Shaders/default.vertex.fx

@@ -21,11 +21,14 @@ attribute vec2 uv2;
 #ifdef VERTEXCOLOR
 attribute vec3 color;
 #endif
+#ifdef BONES
+attribute vec4 matricesIndices;
+attribute vec4 matricesWeights;
+#endif
 
 // Uniforms
 uniform mat4 world;
 uniform mat4 view;
-uniform mat4 worldViewProjection;
 
 #ifdef DIFFUSE
 varying vec2 vDiffuseUV;
@@ -70,6 +73,13 @@ uniform vec2 vBumpInfos;
 uniform mat4 bumpMatrix;
 #endif
 
+#ifdef BONES
+uniform mat4 mBones[BonesPerMesh];
+uniform mat4 viewProjection;
+#else
+uniform mat4 worldViewProjection;
+#endif
+
 // Output
 varying vec3 vPositionW;
 varying vec3 vNormalW;
@@ -143,11 +153,24 @@ vec3 computeReflectionCoords(float mode, vec4 worldPos, vec3 worldNormal)
 #endif
 
 void main(void) {
+	mat4 finalWorld;
+
+#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;
+	mat4 m3 = mBones[int(matricesIndices.w)] * matricesWeights.w;
+
+	finalWorld = world * (m0 + m1 + m2 + m3);
+	gl_Position = viewProjection * finalWorld * vec4(position, 1.0);
+#else
+	finalWorld = world;
 	gl_Position = worldViewProjection * vec4(position, 1.0);
+#endif
 
-	vec4 worldPos = world * vec4(position, 1.0);
+	vec4 worldPos = finalWorld * vec4(position, 1.0);
 	vPositionW = vec3(worldPos);
-	vNormalW = normalize(vec3(world * vec4(normal, 0.0)));
+	vNormalW = normalize(vec3(finalWorld * vec4(normal, 0.0)));
 
 	// Texture coordinates
 #ifndef UV1

+ 25 - 3
Babylon/Shaders/iedefault.vertex.fx

@@ -18,11 +18,14 @@ attribute vec2 uv;
 #ifdef UV2
 attribute vec2 uv2;
 #endif
+#ifdef BONES
+attribute vec4 matricesIndices;
+attribute vec4 matricesWeights;
+#endif
 
 // Uniforms
 uniform mat4 world;
 uniform mat4 view;
-uniform mat4 worldViewProjection;
 
 #ifdef DIFFUSE
 varying vec2 vDiffuseUV;
@@ -62,6 +65,13 @@ uniform vec2 vSpecularInfos;
 uniform mat4 specularMatrix;
 #endif
 
+#ifdef BONES
+uniform mat4 mBones[BonesPerMesh];
+uniform mat4 viewProjection; 
+#else
+uniform mat4 worldViewProjection;
+#endif
+
 // Output
 varying vec3 vPositionW;
 varying vec3 vNormalW;
@@ -119,11 +129,23 @@ vec3 computeReflectionCoords(float mode, vec4 worldPos, vec3 worldNormal)
 #endif
 
 void main(void) {
+	mat4 finalWorld;
+
+#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;
+
+	finalWorld = world * (m0 + m1 + m2);
+	gl_Position = viewProjection * finalWorld * vec4(position, 1.0);
+#else
+	finalWorld = world;
 	gl_Position = worldViewProjection * vec4(position, 1.0);
+#endif
 
-	vec4 worldPos = world * vec4(position, 1.0);
+	vec4 worldPos = finalWorld * vec4(position, 1.0);
 	vPositionW = vec3(worldPos);
-	vNormalW = normalize(vec3(world * vec4(normal, 0.0)));
+	vNormalW = normalize(vec3(finalWorld * vec4(normal, 0.0)));
 
 	// Texture coordinates
 #ifndef UV1

+ 23 - 0
Babylon/Shaders/shadowMap.vertex.fx

@@ -4,11 +4,34 @@ precision mediump float;
 
 // Attribute
 attribute vec3 position;
+#ifdef BONES
+attribute vec4 matricesIndices;
+attribute vec4 matricesWeights;
+#endif
 
 // Uniform
+#ifdef BONES
+uniform mat4 world;
+uniform mat4 mBones[BonesPerMesh];
+uniform mat4 viewProjection;
+#else
 uniform mat4 worldViewProjection;
+#endif
 
 void main(void)
 {
+#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 IE
+	mat4 finalWorld = world * (m0 + m1 + m2);
+#else
+	mat4 m3 = mBones[int(matricesIndices.w)] * matricesWeights.w;
+	mat4 finalWorld = world * (m0 + m1 + m2 + m3);
+#endif
+	gl_Position = viewProjection * finalWorld * vec4(position, 1.0);
+#else
 	gl_Position = worldViewProjection * vec4(position, 1.0);
+#endif
 }

+ 14 - 13
Babylon/Sprites/babylon.sprite.js

@@ -20,7 +20,7 @@
     BABYLON.Sprite.prototype.cellIndex = 0;
     BABYLON.Sprite.prototype.invertU = 0;
     BABYLON.Sprite.prototype.invertV = 0;
-	BABYLON.Sprite.prototype.disposeWhenFinishedAnimating = false;
+    BABYLON.Sprite.prototype.disposeWhenFinishedAnimating = false;
 
     BABYLON.Sprite.prototype._animationStarted = false;
     BABYLON.Sprite.prototype._loopAnimation = false;
@@ -43,7 +43,7 @@
         this._time = 0;
     };
 
-    BABYLON.Sprite.prototype.stopAnimation = function() {
+    BABYLON.Sprite.prototype.stopAnimation = function () {
         this._animationStarted = false;
     };
 
@@ -60,19 +60,20 @@
                     this.cellIndex = this._fromIndex;
                 } else {
                     this._animationStarted = false;
-					if (this.disposeWhenFinishedAnimating) {
-						this.dispose();
-					}
+                    if (this.disposeWhenFinishedAnimating) {
+                        this.dispose();
+                    }
                 }
             }
         }
-    }
+    };
+
+    BABYLON.Sprite.prototype.dispose = function () {
+        for (var i = 0; i < this._manager.sprites.length; i++) {
+            if (this._manager.sprites[i] == this) {
+                this._manager.sprites.splice(i, 1);
+            }
+        }
+    };
 
-	BABYLON.Sprite.prototype.dispose = function() {
-		for (var i = 0; i < this._manager.sprites.length; i++) {
-			if (this._manager.sprites[i] == this) {
-				this._manager.sprites.splice(i, 1);
-			}
-		}
-	}
 })();

+ 6 - 2
Babylon/Sprites/babylon.spriteManager.js

@@ -100,9 +100,13 @@
         var offset = 0;
         this._vertices.length = max * this._vertexStrideSize;
         for (var index = 0; index < max; index++) {
-			if (this.sprites[index] == undefined) { continue; }
             var sprite = this.sprites[index];
+            if (!sprite) {
+                 continue;
+            }
+            
             sprite._animate(deltaTime);
+
             this._appendSpriteVertex(offset++, sprite, 0, 0, rowSize);
             this._appendSpriteVertex(offset++, sprite, 1, 0, rowSize);
             this._appendSpriteVertex(offset++, sprite, 1, 1, rowSize);
@@ -149,7 +153,7 @@
     
     BABYLON.SpriteManager.prototype.dispose = function () {
         if (this._vertexBuffer) {
-            //this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
+            this._scene.getEngine()._releaseBuffer(this._vertexBuffer);
             this._vertexBuffer = null;
         }
 

+ 514 - 0
Babylon/Tools/babylon.database.js

@@ -0,0 +1,514 @@
+var BABYLON = BABYLON || {};
+
+(function () {
+    BABYLON.Database = {};
+    var db = null;
+
+    BABYLON.Database.enableSceneOffline = false;
+    BABYLON.Database.enableTexturesOffline = false;
+    BABYLON.Database.sceneToLoad = "";
+    BABYLON.Database.currentSceneVersion = 0;
+    BABYLON.Database.isUASupportingBlobStorage = true;
+    BABYLON.Database.mustUpdateRessources = false;
+
+    // Handling various flavors of prefixed version of IndexedDB
+    window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB ||
+        window.msIndexedDB;
+    window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction ||
+        window.msIDBTransaction;
+    window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
+
+    function parseURL(url) {
+        var a = document.createElement('a');
+        a.href = url;
+        var fileName = url.substring(url.lastIndexOf("/") + 1, url.length);
+        var absLocation = url.substring(0, url.indexOf(fileName, 0));
+        return absLocation;
+    }
+
+    BABYLON.Database.CheckManifestFile = function (rootUrl, sceneFilename) {
+        var absLocation = parseURL(window.location.href);
+        BABYLON.Database.sceneToLoad = absLocation + rootUrl + sceneFilename;
+        var manifestURL = BABYLON.Database.sceneToLoad + ".manifest";
+
+        var xhr = new XMLHttpRequest();
+
+        xhr.open("GET", manifestURL, false);
+
+        xhr.addEventListener("load", function () {
+            if (xhr.status === 200) {
+                try {
+                    manifestFile = JSON.parse(xhr.response);
+                    BABYLON.Database.enableSceneOffline = manifestFile.enableSceneOffline;
+                    BABYLON.Database.enableTexturesOffline = manifestFile.enableTexturesOffline;
+                    if (manifestFile.version && !isNaN(parseInt(manifestFile.version))) {
+                        BABYLON.Database.currentSceneVersion = manifestFile.version;
+                    }
+                }
+                catch (ex) {
+                    BABYLON.Database.enableSceneOffline = false;
+                    BABYLON.Database.enableTexturesOffline = false;
+                }
+            }
+            else {
+                BABYLON.Database.enableSceneOffline = false;
+                BABYLON.Database.enableTexturesOffline = false;
+            }
+        }, false);
+
+        xhr.addEventListener("error", function (event) {
+            BABYLON.Database.enableSceneOffline = false;
+            BABYLON.Database.enableTexturesOffline = false;
+        }, false);
+
+        xhr.send();
+    };
+
+    BABYLON.Database.OpenAsync = function (successCallback, errorCallback) {
+        if (!window.indexedDB || !(BABYLON.Database.enableSceneOffline || BABYLON.Database.enableTexturesOffline)) {
+            // Your browser doesn't support IndexedDB
+            BABYLON.Database.isSupported = false;
+            if (errorCallback) errorCallback();
+        }
+        else {
+            // If the DB hasn't been opened or created yet
+            if (!db) {
+                BABYLON.Database.hasReachedQuota = false;
+                BABYLON.Database.isSupported = true;
+
+                var request = window.indexedDB.open("babylonjs", 1.0);
+
+                // Could occur if user is blocking the quota for the DB and/or doesn't grant access to IndexedDB
+                request.onerror = function (event) {
+                    BABYLON.Database.isSupported = false;
+                    if (errorCallback) errorCallback();
+                };
+
+                // executes when a version change transaction cannot complete due to other active transactions
+                request.onblocked = function (event) {
+                    console.log("IDB request blocked. Please reload the page.");
+                    if (errorCallback) errorCallback();
+                };
+
+                // DB has been opened successfully
+                request.onsuccess = function (event) {
+                    db = request.result;
+                    isOpeningDB = false;
+                    console.log("DB opened.");
+                    successCallback();
+                };
+
+                // Initialization of the DB. Creating Scenes & Textures stores
+                request.onupgradeneeded = function (event) {
+                    db = event.target.result;
+                    var scenesStore = db.createObjectStore("scenes", { keyPath: "sceneUrl" });
+                    var scenesStore = db.createObjectStore("versions", { keyPath: "sceneUrl" });
+                    var texturesStore = db.createObjectStore("textures", { keyPath: "textureUrl" });
+                };
+            }
+            // DB has already been created and opened
+            else {
+                if (successCallback) successCallback();
+            }
+        }
+    };
+
+    BABYLON.Database.LoadImageFromDB = function (url, image) {
+        var saveAndLoadImage = function (event) {
+            if (!BABYLON.Database.hasReachedQuota && db !== null) {
+                console.log("Saving into DB: " + url);
+                // the texture is not yet in the DB, let's try to save it
+                BABYLON.Database._saveImageIntoDBAsync(url, image);
+            }
+            // If the texture is not in the DB and we've reached the DB quota limit
+            // let's load it directly from the web
+            else {
+                console.log("Image loaded directly from the web: " + url);
+                image.src = url;
+            }
+        };
+        console.log("Currently working on: " + url);
+
+        if (!BABYLON.Database.mustUpdateRessources) {
+            BABYLON.Database._loadImageFromDBAsync(url, image, saveAndLoadImage);
+        }
+        else {
+            saveAndLoadImage();
+        }
+    };
+
+    BABYLON.Database._loadImageFromDBAsync = function (url, image, notInDBCallback) {
+        if (BABYLON.Database.isSupported && db !== null) {
+            var indexeddbUrl = BABYLON.Database.sceneToLoad + "/" + url;
+            var texture;
+            var transaction = db.transaction(["textures"]);
+
+            transaction.onabort = function (event) {
+                image.src = url;
+            };
+
+            transaction.oncomplete = function (event) {
+                var blobTextureURL;
+                if (texture) {
+                    var URL = window.URL || window.webkitURL;
+                    blobTextureURL = URL.createObjectURL(texture.data, { oneTimeOnly: true });
+                    image.src = blobTextureURL;
+                }
+                else {
+                    notInDBCallback();
+                }
+            };
+
+            var getRequest = transaction.objectStore("textures").get(indexeddbUrl);
+
+            getRequest.onsuccess = function (event) {
+                texture = event.target.result;
+            };
+            getRequest.onerror = function (event) {
+                console.log("error loading texture " + indexeddbUrl + " from DB.");
+                image.src = url;
+            };
+        }
+        else {
+            console.log("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
+            image.src = url;
+        }
+    };
+
+    BABYLON.Database._saveImageIntoDBAsync = function (url, image) {
+        if (BABYLON.Database.isSupported) {
+            var indexeddbUrl = BABYLON.Database.sceneToLoad + "/" + url;
+
+            // In case of error (type not supported or quota exceeded), we're at least sending back XHR data to allow texture loading later on
+            var generateBlobUrl = function () {
+                var blobTextureURL;
+
+                if (blob) {
+                    var URL = window.URL || window.webkitURL;
+                    try {
+                        blobTextureURL = URL.createObjectURL(blob, { oneTimeOnly: true });
+                    }
+                    // Chrome is raising a type error if we're setting the oneTimeOnly parameter
+                    catch (ex) {
+                        blobTextureURL = URL.createObjectURL(blob);
+                    }
+                }
+
+                image.src = blobTextureURL;
+            };
+
+            if (BABYLON.Database.isUASupportingBlobStorage) {
+                // Create XHR
+                var xhr = new XMLHttpRequest(),
+                    blob;
+
+                xhr.open("GET", url, true);
+                xhr.responseType = "blob";
+
+                xhr.addEventListener("load", function () {
+                    if (xhr.status === 200) {
+                        // Blob as response (XHR2)
+                        blob = xhr.response;
+
+                        // Open a transaction to the database
+                        var transaction = db.transaction(["textures"], "readwrite");
+
+                        // the transaction could abort because of a QuotaExceededError error
+                        transaction.onabort = function (event) {
+                            try {
+                                if (event.srcElement.error.name === "QuotaExceededError") {
+                                    console.log("QUOTA EXCEEDED ERROR.");
+                                    BABYLON.Database.hasReachedQuota = true;
+                                }
+                            }
+                            catch (ex) { }
+                            generateBlobUrl();
+                        };
+
+                        transaction.oncomplete = function (event) {
+                            generateBlobUrl();
+                            console.log("Saved into DB successfully.");
+                        };
+
+                        var newTexture = {};
+                        newTexture.textureUrl = indexeddbUrl;
+                        newTexture.data = blob;
+
+                        try {
+                            // Put the blob into the dabase
+                            var addRequest = transaction.objectStore("textures").put(newTexture);
+                            addRequest.onsuccess = function (event) {
+
+                            };
+                            addRequest.onerror = function (event) {
+                                generateBlobUrl();
+                            };
+                        }
+                        catch (ex) {
+                            // "DataCloneError" generated by Chrome when you try to inject blob into IndexedDB
+                            if (ex.code === 25) {
+                                BABYLON.Database.isUASupportingBlobStorage = false;
+                                console.log("Exception. Returning URL because UA doesn't support Blob in IDB.");
+                            }
+                            image.src = url;
+                        }
+                    }
+                    else {
+                        image.src = url;
+                    }
+                }, false);
+
+                xhr.addEventListener("error", function (event) {
+                    console.log("error on XHR request.");
+                    image.src = url;
+                }, false);
+
+                xhr.send();
+            }
+            else {
+                console.log("Directly returning URL because UA doesn't support Blob in IDB.");
+                image.src = url;
+            }
+        }
+        else {
+            console.log("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
+            image.src = url;
+        }
+    };
+
+    BABYLON.Database._checkVersionFromDB = function (versionLoaded) {
+        var updateVersion = function (event) {
+            // the version is not yet in the DB or we need to update it
+            BABYLON.Database._saveVersionIntoDBAsync(versionLoaded);
+        };
+        BABYLON.Database._loadVersionFromDBAsync(versionLoaded, updateVersion);
+    };
+
+    BABYLON.Database._loadVersionFromDBAsync = function (callback, updateInDBCallback) {
+        if (BABYLON.Database.isSupported) {
+            var version;
+            var transaction = db.transaction(["versions"]);
+
+            transaction.oncomplete = function (event) {
+                if (version) {
+                    // If the version in the JSON file is > than the version in DB
+                    if (BABYLON.Database.currentSceneVersion > version.data) {
+                        console.log("Version change detected. Need to update DB with new ressources.");
+                        BABYLON.Database.mustUpdateRessources = true;
+                        updateInDBCallback();
+                    }
+                    else {
+                        callback(version.data);
+                    }
+                }
+                // version was not found in DB
+                else {
+                    BABYLON.Database.mustUpdateRessources = true;
+                    updateInDBCallback();
+                }
+            };
+
+            transaction.onabort = function (event) {
+                callback(-1);
+            };
+
+            var getRequest = transaction.objectStore("versions").get(BABYLON.Database.sceneToLoad);
+
+            getRequest.onsuccess = function (event) {
+                version = event.target.result;
+            };
+            getRequest.onerror = function (event) {
+                console.log("error loading version for scene " + BABYLON.Database.sceneToLoad + " from DB.");
+                callback(-1);
+            };
+        }
+        else {
+            console.log("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
+            callback(-1);
+        }
+    };
+
+    BABYLON.Database._saveVersionIntoDBAsync = function (callback) {
+        if (BABYLON.Database.isSupported && !BABYLON.Database.hasReachedQuota) {
+            // Open a transaction to the database
+            var transaction = db.transaction(["versions"], "readwrite");
+
+            // the transaction could abort because of a QuotaExceededError error
+            transaction.onabort = function (event) {
+                try {
+                    if (event.srcElement.error.name === "QuotaExceededError") {
+                        BABYLON.Database.hasReachedQuota = true;
+                    }
+                }
+                catch (ex) { }
+                callback(-1);
+            };
+
+            transaction.oncomplete = function (event) {
+                callback(BABYLON.Database.currentSceneVersion);
+            };
+
+            var newVersion = {};
+            newVersion.sceneUrl = BABYLON.Database.sceneToLoad;
+            newVersion.data = BABYLON.Database.currentSceneVersion;
+
+            try {
+                // Put the scene into the database
+                var addRequest = transaction.objectStore("versions").put(newVersion);
+                addRequest.onsuccess = function (event) {
+
+                };
+                addRequest.onerror = function (event) {
+                    console.log("error add request");
+                };
+            }
+            catch (ex) {
+                callback(-1);
+            }
+        }
+        else {
+            callback(-1);
+        }
+    };
+
+    BABYLON.Database.LoadSceneFromDB = function (sceneLoaded, progressCallBack) {
+        var saveAndLoadScene = function (event) {
+            // the scene is not yet in the DB, let's try to save it
+            BABYLON.Database._saveSceneIntoDBAsync(sceneLoaded, progressCallBack);
+        };
+
+        BABYLON.Database._checkVersionFromDB(function (version) {
+            console.log("Version: " + version);
+            if (!BABYLON.Database.mustUpdateRessources) {
+                BABYLON.Database._loadSceneFromDBAsync(sceneLoaded, saveAndLoadScene);
+            }
+            else {
+                BABYLON.Database._saveSceneIntoDBAsync(sceneLoaded, progressCallBack);
+            }
+        });
+    };
+
+    BABYLON.Database._loadSceneFromDBAsync = function (callback, notInDBCallback) {
+        if (BABYLON.Database.isSupported) {
+            var scene;
+            var transaction = db.transaction(["scenes"]);
+
+            transaction.oncomplete = function (event) {
+                if (scene) {
+                    callback(scene.data);
+                }
+                // scene was not found in DB
+                else {
+                    notInDBCallback();
+                }
+            };
+
+            transaction.onabort = function (event) {
+                notInDBCallback();
+            };
+
+            var getRequest = transaction.objectStore("scenes").get(BABYLON.Database.sceneToLoad);
+
+            getRequest.onsuccess = function (event) {
+                scene = event.target.result;
+            };
+            getRequest.onerror = function (event) {
+                console.log("error loading scene " + BABYLON.Database.sceneToLoad + " from DB.");
+                notInDBCallback();
+            };
+        }
+        else {
+            console.log("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
+            callback();
+        }
+    };
+
+    BABYLON.Database._saveSceneIntoDBAsync = function (callback, progressCallback) {
+        if (BABYLON.Database.isSupported) {
+            // Create XHR
+            var xhr = new XMLHttpRequest(), sceneText;
+
+            xhr.open("GET", BABYLON.Database.sceneToLoad, true);
+
+            xhr.onprogress = progressCallback;
+
+            xhr.addEventListener("load", function () {
+                if (xhr.status === 200) {
+                    // Blob as response (XHR2)
+                    sceneText = xhr.responseText;
+
+                    if (!BABYLON.Database.hasReachedQuota) {
+                        // Open a transaction to the database
+                        var transaction = db.transaction(["scenes"], "readwrite");
+
+                        // the transaction could abort because of a QuotaExceededError error
+                        transaction.onabort = function (event) {
+                            try {
+                                if (event.srcElement.error.name === "QuotaExceededError") {
+                                    BABYLON.Database.hasReachedQuota = true;
+                                }
+                            }
+                            catch (ex) { }
+                            callback(sceneText);
+                        };
+
+                        transaction.oncomplete = function (event) {
+                            callback(sceneText);
+                        };
+
+                        var newScene = {};
+                        newScene.sceneUrl = BABYLON.Database.sceneToLoad;
+                        newScene.data = sceneText;
+                        newScene.version = BABYLON.Database.currentSceneVersion;
+
+                        try {
+                            // Put the scene into the database
+                            var addRequest = transaction.objectStore("scenes").put(newScene);
+                            addRequest.onsuccess = function (event) {
+
+                            };
+                            addRequest.onerror = function (event) {
+                                console.log("error add request");
+                            };
+                        }
+                        catch (ex) {
+                            callback(sceneText);
+                        }
+                    }
+                    else {
+                        callback(sceneText);
+                    }
+                }
+                else {
+                    callback();
+                }
+            }, false);
+
+            xhr.addEventListener("error", function (event) {
+                console.log("error on XHR request.");
+                callback();
+            }, false);
+
+            xhr.send();
+        }
+        else {
+            console.log("Error: IndexedDB not supported by your browser or BabylonJS Database is not open.");
+            callback();
+        }
+    };
+
+    // Called to close the db and reset the objects
+    BABYLON.Database.Release = function () {
+        if (db) {
+            db.close();
+            db = null;
+            console.log("DB closed.");
+            BABYLON.Database.hasReachedQuota = false;
+            BABYLON.Database.mustUpdateRessources = false;
+            BABYLON.Database.enableSceneOffline = false;
+            BABYLON.Database.enableTexturesOffline = false;
+            BABYLON.Database.sceneToLoad = "";
+            BABYLON.Database.currentSceneVersion = 0;
+        }
+    };
+})();

+ 218 - 163
Babylon/Tools/babylon.math.js

@@ -13,21 +13,17 @@
         var d = 0.0;
         var maxValue = Number.MAX_VALUE;
 
-        if (Math.abs(this.direction.x) < 0.0000001)
-        {
-            if (this.origin.x < box.minimum.x || this.origin.x > box.maximum.x)
-            {
+        if (Math.abs(this.direction.x) < 0.0000001) {
+            if (this.origin.x < box.minimum.x || this.origin.x > box.maximum.x) {
                 return false;
             }
         }
-        else
-        {
+        else {
             var inv = 1.0 / this.direction.x;
             var min = (box.minimum.x - this.origin.x) * inv;
             var max = (box.maximum.x - this.origin.x) * inv;
 
-            if (min > max)
-            {
+            if (min > max) {
                 var temp = min;
                 min = max;
                 max = temp;
@@ -36,27 +32,22 @@
             d = Math.max(min, d);
             maxValue = Math.min(max, maxValue);
 
-            if (d > maxValue)
-            {
+            if (d > maxValue) {
                 return false;
             }
         }
 
-        if (Math.abs(this.direction.y) < 0.0000001)
-        {
-            if (this.origin.y < box.minimum.y || this.origin.y > box.maximum.y)
-            {
+        if (Math.abs(this.direction.y) < 0.0000001) {
+            if (this.origin.y < box.minimum.y || this.origin.y > box.maximum.y) {
                 return false;
             }
         }
-        else
-        {
+        else {
             var inv = 1.0 / this.direction.y;
             var min = (box.minimum.y - this.origin.y) * inv;
             var max = (box.maximum.y - this.origin.y) * inv;
 
-            if (min > max)
-            {
+            if (min > max) {
                 var temp = min;
                 min = max;
                 max = temp;
@@ -65,27 +56,22 @@
             d = Math.max(min, d);
             maxValue = Math.min(max, maxValue);
 
-            if (d > maxValue)
-            {
+            if (d > maxValue) {
                 return false;
             }
         }
 
-        if (Math.abs(this.direction.z) < 0.0000001)
-        {
-            if (this.origin.z < box.minimum.z || this.origin.z > box.maximum.z)
-            {
+        if (Math.abs(this.direction.z) < 0.0000001) {
+            if (this.origin.z < box.minimum.z || this.origin.z > box.maximum.z) {
                 return false;
             }
         }
-        else
-        {
+        else {
             var inv = 1.0 / this.direction.z;
             var min = (box.minimum.z - this.origin.z) * inv;
             var max = (box.maximum.z - this.origin.z) * inv;
 
-            if (min > max)
-            {
+            if (min > max) {
                 var temp = min;
                 min = max;
                 max = temp;
@@ -94,14 +80,13 @@
             d = Math.max(min, d);
             maxValue = Math.min(max, maxValue);
 
-            if (d > maxValue)
-            {
+            if (d > maxValue) {
                 return false;
             }
         }
-        return true;        
+        return true;
     };
-    
+
     BABYLON.Ray.prototype.intersectsSphere = function (sphere) {
         var x = sphere.center.x - this.origin.x;
         var y = sphere.center.y - this.origin.y;
@@ -203,7 +188,7 @@
     BABYLON.Color3.prototype.multiply = function (otherColor) {
         return new BABYLON.Color3(this.r * otherColor.r, this.g * otherColor.g, this.b * otherColor.b);
     };
-    
+
     BABYLON.Color3.prototype.multiplyToRef = function (otherColor, result) {
         result.r = this.r * otherColor.r;
         result.g = this.g * otherColor.g;
@@ -213,27 +198,27 @@
     BABYLON.Color3.prototype.equals = function (otherColor) {
         return this.r === otherColor.r && this.g === otherColor.g && this.b === otherColor.b;
     };
-    
+
     BABYLON.Color3.prototype.scale = function (scale) {
         return new BABYLON.Color3(this.r * scale, this.g * scale, this.b * scale);
     };
-    
+
     BABYLON.Color3.prototype.scaleToRef = function (scale, result) {
         result.r = this.r * scale;
         result.g = this.g * scale;
         result.b = this.b * scale;
     };
-    
+
     BABYLON.Color3.prototype.clone = function () {
         return new BABYLON.Color3(this.r, this.g, this.b);
     };
-    
+
     BABYLON.Color3.prototype.copyFrom = function (source) {
         this.r = source.r;
         this.g = source.g;
         this.b = source.b;
     };
-    
+
     BABYLON.Color3.prototype.copyFromFloats = function (r, g, b) {
         this.r = r;
         this.g = g;
@@ -243,7 +228,7 @@
     // Statics
     BABYLON.Color3.FromArray = function (array) {
         return new BABYLON.Color3(array[0], array[1], array[2]);
-    };   
+    };
 
     ////////////////////////////////// Color4 //////////////////////////////////
 
@@ -253,7 +238,7 @@
         this.b = initialB;
         this.a = initialA;
     };
-    
+
     // Operators
     BABYLON.Color4.prototype.addInPlace = function (right) {
         this.r += right.r;
@@ -261,26 +246,26 @@
         this.b += right.b;
         this.a += right.a;
     };
-    
+
     BABYLON.Color4.prototype.add = function (right) {
         return new BABYLON.Color4(this.r + right.r, this.g + right.g, this.b + right.b, this.a + right.a);
     };
-    
+
     BABYLON.Color4.prototype.subtract = function (right) {
         return new BABYLON.Color4(this.r - right.r, this.g - right.g, this.b - right.b, this.a - right.a);
     };
-    
+
     BABYLON.Color4.prototype.subtractToRef = function (right, result) {
         result.r = this.r - right.r;
         result.g = this.g - right.g;
         result.b = this.b - right.b;
         result.a = this.a - right.a;
     };
-    
+
     BABYLON.Color4.prototype.scale = function (scale) {
         return new BABYLON.Color4(this.r * scale, this.g * scale, this.b * scale, this.a * scale);
     };
-    
+
     BABYLON.Color4.prototype.scaleToRef = function (scale, result) {
         result.r = this.r * scale;
         result.g = this.g * scale;
@@ -291,34 +276,34 @@
     BABYLON.Color4.prototype.toString = function () {
         return "{R: " + this.r + " G:" + this.g + " B:" + this.b + " A:" + this.a + "}";
     };
-    
+
     BABYLON.Color4.prototype.clone = function () {
         return new BABYLON.Color4(this.r, this.g, this.b, this.a);
     };
-    
+
     // Statics
-    BABYLON.Color4.Lerp = function(left, right, amount) {
+    BABYLON.Color4.Lerp = function (left, right, amount) {
         var result = new BABYLON.Color4(0, 0, 0, 0);
 
         BABYLON.Color4.LerpToRef(left, right, amount, result);
 
         return result;
     };
-    
+
     BABYLON.Color4.LerpToRef = function (left, right, amount, result) {
         result.r = left.r + (right.r - left.r) * amount;
         result.g = left.g + (right.g - left.g) * amount;
         result.b = left.b + (right.b - left.b) * amount;
         result.a = left.a + (right.a - left.a) * amount;
     };
-    
+
     BABYLON.Color4.FromArray = function (array, offset) {
         if (!offset) {
             offset = 0;
         }
 
         return new BABYLON.Color4(array[offset], array[offset + 1], array[offset + 2], array[offset + 3]);
-    };    
+    };
 
     ////////////////////////////////// Vector2 //////////////////////////////////
 
@@ -343,7 +328,7 @@
     BABYLON.Vector2.prototype.negate = function () {
         return new BABYLON.Vector2(-this.x, -this.y);
     };
-    
+
     BABYLON.Vector2.prototype.scaleInPlace = function (scale) {
         this.x *= scale;
         this.y *= scale;
@@ -378,7 +363,7 @@
         this.x *= num;
         this.y *= num;
     };
-    
+
     BABYLON.Vector2.prototype.clone = function () {
         return new BABYLON.Vector2(this.x, this.y);
     };
@@ -491,22 +476,28 @@
     };
 
     // Operators
+    BABYLON.Vector3.prototype.toArray = function (array, index) {
+        array[index] = this.x;
+        array[index + 1] = this.y;
+        array[index + 2] = this.z;
+    };
+
     BABYLON.Vector3.prototype.addInPlace = function (otherVector) {
         this.x += otherVector.x;
         this.y += otherVector.y;
         this.z += otherVector.z;
     };
-    
+
     BABYLON.Vector3.prototype.add = function (otherVector) {
         return new BABYLON.Vector3(this.x + otherVector.x, this.y + otherVector.y, this.z + otherVector.z);
     };
-    
+
     BABYLON.Vector3.prototype.addToRef = function (otherVector, result) {
         result.x = this.x + otherVector.x;
         result.y = this.y + otherVector.y;
         result.z = this.z + otherVector.z;
     };
-    
+
     BABYLON.Vector3.prototype.subtractInPlace = function (otherVector) {
         this.x -= otherVector.x;
         this.y -= otherVector.y;
@@ -516,13 +507,13 @@
     BABYLON.Vector3.prototype.subtract = function (otherVector) {
         return new BABYLON.Vector3(this.x - otherVector.x, this.y - otherVector.y, this.z - otherVector.z);
     };
-    
+
     BABYLON.Vector3.prototype.subtractToRef = function (otherVector, result) {
         result.x = this.x - otherVector.x;
         result.y = this.y - otherVector.y;
         result.z = this.z - otherVector.z;
     };
-    
+
     BABYLON.Vector3.prototype.subtractFromFloats = function (x, y, z) {
         return new BABYLON.Vector3(this.x - x, this.y - y, this.z - z);
     };
@@ -536,7 +527,7 @@
     BABYLON.Vector3.prototype.negate = function () {
         return new BABYLON.Vector3(-this.x, -this.y, -this.z);
     };
-    
+
     BABYLON.Vector3.prototype.scaleInPlace = function (scale) {
         this.x *= scale;
         this.y *= scale;
@@ -546,7 +537,7 @@
     BABYLON.Vector3.prototype.scale = function (scale) {
         return new BABYLON.Vector3(this.x * scale, this.y * scale, this.z * scale);
     };
-    
+
     BABYLON.Vector3.prototype.scaleToRef = function (scale, result) {
         result.x = this.x * scale;
         result.y = this.y * scale;
@@ -556,7 +547,7 @@
     BABYLON.Vector3.prototype.equals = function (otherVector) {
         return this.x === otherVector.x && this.y === otherVector.y && this.z === otherVector.z;
     };
-    
+
     BABYLON.Vector3.prototype.equalsToFloats = function (x, y, z) {
         return this.x === x && this.y === y && this.z === z;
     };
@@ -570,13 +561,13 @@
     BABYLON.Vector3.prototype.multiply = function (otherVector) {
         return new BABYLON.Vector3(this.x * otherVector.x, this.y * otherVector.y, this.z * otherVector.z);
     };
-    
+
     BABYLON.Vector3.prototype.multiplyToRef = function (otherVector, result) {
         result.x = this.x * otherVector.x;
         result.y = this.y * otherVector.y;
         result.z = this.z * otherVector.z;
     };
-    
+
     BABYLON.Vector3.prototype.multiplyByFloats = function (x, y, z) {
         return new BABYLON.Vector3(this.x * x, this.y * y, this.z * z);
     };
@@ -584,7 +575,7 @@
     BABYLON.Vector3.prototype.divide = function (otherVector) {
         return new BABYLON.Vector3(this.x / otherVector.x, this.y / otherVector.y, this.z / otherVector.z);
     };
-    
+
     BABYLON.Vector3.prototype.divideToRef = function (otherVector, result) {
         result.x = this.x / otherVector.x;
         result.y = this.y / otherVector.y;
@@ -617,13 +608,13 @@
     BABYLON.Vector3.prototype.clone = function () {
         return new BABYLON.Vector3(this.x, this.y, this.z);
     };
-    
+
     BABYLON.Vector3.prototype.copyFrom = function (source) {
         this.x = source.x;
         this.y = source.y;
         this.z = source.z;
     };
-    
+
     BABYLON.Vector3.prototype.copyFromFloats = function (x, y, z) {
         this.x = x;
         this.y = y;
@@ -638,7 +629,7 @@
 
         return new BABYLON.Vector3(array[offset], array[offset + 1], array[offset + 2]);
     };
-    
+
     BABYLON.Vector3.FromArrayToRef = function (array, offset, result) {
         if (!offset) {
             offset = 0;
@@ -648,7 +639,7 @@
         result.y = array[offset + 1];
         result.z = array[offset + 2];
     };
-    
+
     BABYLON.Vector3.FromFloatsToRef = function (x, y, z, result) {
         result.x = x;
         result.y = y;
@@ -670,7 +661,7 @@
 
         return result;
     };
-    
+
     BABYLON.Vector3.TransformCoordinatesToRef = function (vector, transformation, result) {
         var x = (vector.x * transformation.m[0]) + (vector.y * transformation.m[4]) + (vector.z * transformation.m[8]) + transformation.m[12];
         var y = (vector.x * transformation.m[1]) + (vector.y * transformation.m[5]) + (vector.z * transformation.m[9]) + transformation.m[13];
@@ -681,8 +672,8 @@
         result.y = y / w;
         result.z = z / w;
     };
-    
-    BABYLON.Vector3.TransformCoordinatesFromFloatsToRef = function (x, y ,z, transformation, result) {
+
+    BABYLON.Vector3.TransformCoordinatesFromFloatsToRef = function (x, y, z, transformation, result) {
         var rx = (x * transformation.m[0]) + (y * transformation.m[4]) + (z * transformation.m[8]) + transformation.m[12];
         var ry = (x * transformation.m[1]) + (y * transformation.m[5]) + (z * transformation.m[9]) + transformation.m[13];
         var rz = (x * transformation.m[2]) + (y * transformation.m[6]) + (z * transformation.m[10]) + transformation.m[14];
@@ -700,7 +691,7 @@
 
         return result;
     };
-    
+
     BABYLON.Vector3.TransformNormalToRef = function (vector, transformation, result) {
         result.x = (vector.x * transformation.m[0]) + (vector.y * transformation.m[4]) + (vector.z * transformation.m[8]);
         result.y = (vector.x * transformation.m[1]) + (vector.y * transformation.m[5]) + (vector.z * transformation.m[9]);
@@ -782,7 +773,7 @@
 
         return result;
     };
-    
+
     BABYLON.Vector3.CrossToRef = function (left, right, result) {
         result.x = left.y * right.z - left.z * right.y;
         result.y = left.z * right.x - left.x * right.z;
@@ -794,7 +785,7 @@
         BABYLON.Vector3.NormalizeToRef(vector, result);
         return result;
     };
-    
+
     BABYLON.Vector3.NormalizeToRef = function (vector, result) {
         result.copyFrom(vector);
         result.normalize();
@@ -840,7 +831,7 @@
 
         return (x * x) + (y * y) + (z * z);
     };
-    
+
     ////////////////////////////////// Quaternion //////////////////////////////////
 
     BABYLON.Quaternion = function (initialX, initialY, initialZ, initialW) {
@@ -854,33 +845,68 @@
         return "{X: " + this.x + " Y:" + this.y + " Z:" + this.z + " W:" + this.w + "}";
     };
     
+    BABYLON.Quaternion.prototype.equals = function (otherQuaternion) {
+        return this.x === otherQuaternion.x && this.y === otherQuaternion.y && this.z === otherQuaternion.z && this.w === otherQuaternion.w;
+    };
+
     BABYLON.Quaternion.prototype.clone = function () {
         return new BABYLON.Quaternion(this.x, this.y, this.z, this.w);
     };
+    
+    BABYLON.Quaternion.prototype.copyFrom = function (other) {
+        this.x = other.x;
+        this.y = other.y;
+        this.z = other.z;
+        this.w = other.w;
+    };
 
-    BABYLON.Quaternion.prototype.add = function(other) {
+    BABYLON.Quaternion.prototype.add = function (other) {
         return new BABYLON.Quaternion(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w);
     };
-    
+
     BABYLON.Quaternion.prototype.scale = function (value) {
         return new BABYLON.Quaternion(this.x * value, this.y * value, this.z * value, this.w * value);
     };
-    
-    BABYLON.Quaternion.prototype.toEulerAngles = function () {
-        var q0 = this.x;
-        var q1 = this.y;
-        var q2 = this.y;
-        var q3 = this.w;
 
-        var x = Math.atan2(2 * (q0 * q1 + q2 * q3), 1 - 2 * (q1 * q1 + q2 * q2));
-        var y = Math.asin(2 * (q0 * q2 - q3 * q1));
-        var z = Math.atan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2 * q2 + q3 * q3));
+    BABYLON.Quaternion.prototype.length = function () {
+        return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z) + (this.w * this.w));
+    };
 
-        return new BABYLON.Vector3(x, y, z);
+    BABYLON.Quaternion.prototype.normalize = function () {
+        var length = 1.0 / this.length();
+        this.x *= length;
+        this.y *= length;
+        this.z *= length;
+        this.w *= length;
     };
-    
-    BABYLON.Quaternion.prototype.toRotationMatrix = function(result)
-    {
+
+    BABYLON.Quaternion.prototype.toEulerAngles = function () {
+        var qx = this.x;
+        var qy = this.y;
+        var qz = this.z;
+        var qw = this.w;
+
+        var sqx = qx * qx;
+        var sqy = qy * qy;
+        var sqz = qz * qz;
+
+        var yaw = Math.atan2(2.0 * (qy * qw - qx * qz), 1.0 - 2.0 * (sqy + sqz));
+        var pitch = Math.asin(2.0 * (qx * qy + qz * qw));
+        var roll = Math.atan2(2.0 * (qx * qw - qy * qz), 1.0 - 2.0 * (sqx + sqz));
+
+        var gimbaLockTest = qx * qy + qz * qw;
+        if (gimbaLockTest > 0.499) {
+            yaw = 2.0 * Math.atan2(qx, qw);
+            roll = 0;
+        } else if (gimbaLockTest < -0.499) {
+            yaw = -2.0 * Math.atan2(qx, qw);
+            roll = 0;
+        }
+
+        return new BABYLON.Vector3(pitch, yaw, roll);
+    };
+
+    BABYLON.Quaternion.prototype.toRotationMatrix = function (result) {
         var xx = this.x * this.x;
         var yy = this.y * this.y;
         var zz = this.z * this.z;
@@ -908,7 +934,7 @@
         result.m[14] = 0;
         result.m[15] = 1.0;
     };
-    
+
     // Statics
     BABYLON.Quaternion.FromArray = function (array, offset) {
         if (!offset) {
@@ -918,7 +944,7 @@
         return new BABYLON.Quaternion(array[offset], array[offset + 1], array[offset + 2], array[offset + 3]);
     };
 
-    BABYLON.Quaternion.RotationYawPitchRoll = function(yaw, pitch, roll) {
+    BABYLON.Quaternion.RotationYawPitchRoll = function (yaw, pitch, roll) {
         var result = new BABYLON.Quaternion();
 
         BABYLON.Quaternion.RotationYawPitchRollToRef(yaw, pitch, roll, result);
@@ -945,26 +971,23 @@
     };
 
 
-    BABYLON.Quaternion.Slerp = function(left, right, amount) {
+    BABYLON.Quaternion.Slerp = function (left, right, amount) {
         var num2;
         var num3;
         var num = amount;
-        var num4 = (((left.x * right.x) + (left.y * right.y)) + (left.z * right.z)) + (left.w * right.w);        
+        var num4 = (((left.x * right.x) + (left.y * right.y)) + (left.z * right.z)) + (left.w * right.w);
         var flag = false;
-        
-        if (num4 < 0)
-        {
+
+        if (num4 < 0) {
             flag = true;
             num4 = -num4;
         }
-        
-        if (num4 > 0.999999)
-        {
+
+        if (num4 > 0.999999) {
             num3 = 1 - num;
             num2 = flag ? -num : num;
         }
-        else
-        {
+        else {
             var num5 = Math.acos(num4);
             var num6 = (1.0 / Math.sin(num5));
             num3 = (Math.sin((1.0 - num) * num5)) * num6;
@@ -975,7 +998,7 @@
     };
 
     ////////////////////////////////// Matrix //////////////////////////////////
-    
+
     if (!BABYLON.MatrixType) {
         BABYLON.MatrixType = (typeof Float32Array !== 'undefined') ? Float32Array : Array;
     }
@@ -1017,6 +1040,10 @@
     };
 
     BABYLON.Matrix.prototype.invert = function () {
+        this.invertToRef(this);
+    };
+
+    BABYLON.Matrix.prototype.invertToRef = function (other) {
         var l1 = this.m[0];
         var l2 = this.m[1];
         var l3 = this.m[2];
@@ -1057,22 +1084,22 @@
         var l38 = (l5 * l11) - (l7 * l9);
         var l39 = (l5 * l10) - (l6 * l9);
 
-        this.m[0] = l23 * l27;
-        this.m[4] = l24 * l27;
-        this.m[8] = l25 * l27;
-        this.m[12] = l26 * l27;
-        this.m[1] = -(((l2 * l17) - (l3 * l18)) + (l4 * l19)) * l27;
-        this.m[5] = (((l1 * l17) - (l3 * l20)) + (l4 * l21)) * l27;
-        this.m[9] = -(((l1 * l18) - (l2 * l20)) + (l4 * l22)) * l27;
-        this.m[13] = (((l1 * l19) - (l2 * l21)) + (l3 * l22)) * l27;
-        this.m[2] = (((l2 * l28) - (l3 * l29)) + (l4 * l30)) * l27;
-        this.m[6] = -(((l1 * l28) - (l3 * l31)) + (l4 * l32)) * l27;
-        this.m[10] = (((l1 * l29) - (l2 * l31)) + (l4 * l33)) * l27;
-        this.m[14] = -(((l1 * l30) - (l2 * l32)) + (l3 * l33)) * l27;
-        this.m[3] = -(((l2 * l34) - (l3 * l35)) + (l4 * l36)) * l27;
-        this.m[7] = (((l1 * l34) - (l3 * l37)) + (l4 * l38)) * l27;
-        this.m[11] = -(((l1 * l35) - (l2 * l37)) + (l4 * l39)) * l27;
-        this.m[15] = (((l1 * l36) - (l2 * l38)) + (l3 * l39)) * l27;
+        other.m[0] = l23 * l27;
+        other.m[4] = l24 * l27;
+        other.m[8] = l25 * l27;
+        other.m[12] = l26 * l27;
+        other.m[1] = -(((l2 * l17) - (l3 * l18)) + (l4 * l19)) * l27;
+        other.m[5] = (((l1 * l17) - (l3 * l20)) + (l4 * l21)) * l27;
+        other.m[9] = -(((l1 * l18) - (l2 * l20)) + (l4 * l22)) * l27;
+        other.m[13] = (((l1 * l19) - (l2 * l21)) + (l3 * l22)) * l27;
+        other.m[2] = (((l2 * l28) - (l3 * l29)) + (l4 * l30)) * l27;
+        other.m[6] = -(((l1 * l28) - (l3 * l31)) + (l4 * l32)) * l27;
+        other.m[10] = (((l1 * l29) - (l2 * l31)) + (l4 * l33)) * l27;
+        other.m[14] = -(((l1 * l30) - (l2 * l32)) + (l3 * l33)) * l27;
+        other.m[3] = -(((l2 * l34) - (l3 * l35)) + (l4 * l36)) * l27;
+        other.m[7] = (((l1 * l34) - (l3 * l37)) + (l4 * l38)) * l27;
+        other.m[11] = -(((l1 * l35) - (l2 * l37)) + (l4 * l39)) * l27;
+        other.m[15] = (((l1 * l36) - (l2 * l38)) + (l3 * l39)) * l27;
     };
 
     BABYLON.Matrix.prototype.multiply = function (other) {
@@ -1082,27 +1109,37 @@
 
         return result;
     };
-    
+
+    BABYLON.Matrix.prototype.copyFrom = function (other) {
+        for (var index = 0; index < 16; index++) {
+            this.m[index] = other.m[index];
+        }
+    };
+
     BABYLON.Matrix.prototype.multiplyToRef = function (other, result) {
-        result.m[0] = this.m[0] * other.m[0] + this.m[1] * other.m[4] + this.m[2] * other.m[8] + this.m[3] * other.m[12];
-        result.m[1] = this.m[0] * other.m[1] + this.m[1] * other.m[5] + this.m[2] * other.m[9] + this.m[3] * other.m[13];
-        result.m[2] = this.m[0] * other.m[2] + this.m[1] * other.m[6] + this.m[2] * other.m[10] + this.m[3] * other.m[14];
-        result.m[3] = this.m[0] * other.m[3] + this.m[1] * other.m[7] + this.m[2] * other.m[11] + this.m[3] * other.m[15];
+        this.multiplyToArray(other, result.m, 0);
+    };
+
+    BABYLON.Matrix.prototype.multiplyToArray = function (other, result, offset) {
+        result[offset] = this.m[0] * other.m[0] + this.m[1] * other.m[4] + this.m[2] * other.m[8] + this.m[3] * other.m[12];
+        result[offset + 1] = this.m[0] * other.m[1] + this.m[1] * other.m[5] + this.m[2] * other.m[9] + this.m[3] * other.m[13];
+        result[offset + 2] = this.m[0] * other.m[2] + this.m[1] * other.m[6] + this.m[2] * other.m[10] + this.m[3] * other.m[14];
+        result[offset + 3] = this.m[0] * other.m[3] + this.m[1] * other.m[7] + this.m[2] * other.m[11] + this.m[3] * other.m[15];
 
-        result.m[4] = this.m[4] * other.m[0] + this.m[5] * other.m[4] + this.m[6] * other.m[8] + this.m[7] * other.m[12];
-        result.m[5] = this.m[4] * other.m[1] + this.m[5] * other.m[5] + this.m[6] * other.m[9] + this.m[7] * other.m[13];
-        result.m[6] = this.m[4] * other.m[2] + this.m[5] * other.m[6] + this.m[6] * other.m[10] + this.m[7] * other.m[14];
-        result.m[7] = this.m[4] * other.m[3] + this.m[5] * other.m[7] + this.m[6] * other.m[11] + this.m[7] * other.m[15];
+        result[offset + 4] = this.m[4] * other.m[0] + this.m[5] * other.m[4] + this.m[6] * other.m[8] + this.m[7] * other.m[12];
+        result[offset + 5] = this.m[4] * other.m[1] + this.m[5] * other.m[5] + this.m[6] * other.m[9] + this.m[7] * other.m[13];
+        result[offset + 6] = this.m[4] * other.m[2] + this.m[5] * other.m[6] + this.m[6] * other.m[10] + this.m[7] * other.m[14];
+        result[offset + 7] = this.m[4] * other.m[3] + this.m[5] * other.m[7] + this.m[6] * other.m[11] + this.m[7] * other.m[15];
 
-        result.m[8] = this.m[8] * other.m[0] + this.m[9] * other.m[4] + this.m[10] * other.m[8] + this.m[11] * other.m[12];
-        result.m[9] = this.m[8] * other.m[1] + this.m[9] * other.m[5] + this.m[10] * other.m[9] + this.m[11] * other.m[13];
-        result.m[10] = this.m[8] * other.m[2] + this.m[9] * other.m[6] + this.m[10] * other.m[10] + this.m[11] * other.m[14];
-        result.m[11] = this.m[8] * other.m[3] + this.m[9] * other.m[7] + this.m[10] * other.m[11] + this.m[11] * other.m[15];
+        result[offset + 8] = this.m[8] * other.m[0] + this.m[9] * other.m[4] + this.m[10] * other.m[8] + this.m[11] * other.m[12];
+        result[offset + 9] = this.m[8] * other.m[1] + this.m[9] * other.m[5] + this.m[10] * other.m[9] + this.m[11] * other.m[13];
+        result[offset + 10] = this.m[8] * other.m[2] + this.m[9] * other.m[6] + this.m[10] * other.m[10] + this.m[11] * other.m[14];
+        result[offset + 11] = this.m[8] * other.m[3] + this.m[9] * other.m[7] + this.m[10] * other.m[11] + this.m[11] * other.m[15];
 
-        result.m[12] = this.m[12] * other.m[0] + this.m[13] * other.m[4] + this.m[14] * other.m[8] + this.m[15] * other.m[12];
-        result.m[13] = this.m[12] * other.m[1] + this.m[13] * other.m[5] + this.m[14] * other.m[9] + this.m[15] * other.m[13];
-        result.m[14] = this.m[12] * other.m[2] + this.m[13] * other.m[6] + this.m[14] * other.m[10] + this.m[15] * other.m[14];
-        result.m[15] = this.m[12] * other.m[3] + this.m[13] * other.m[7] + this.m[14] * other.m[11] + this.m[15] * other.m[15];
+        result[offset + 12] = this.m[12] * other.m[0] + this.m[13] * other.m[4] + this.m[14] * other.m[8] + this.m[15] * other.m[12];
+        result[offset + 13] = this.m[12] * other.m[1] + this.m[13] * other.m[5] + this.m[14] * other.m[9] + this.m[15] * other.m[13];
+        result[offset + 14] = this.m[12] * other.m[2] + this.m[13] * other.m[6] + this.m[14] * other.m[10] + this.m[15] * other.m[14];
+        result[offset + 15] = this.m[12] * other.m[3] + this.m[13] * other.m[7] + this.m[14] * other.m[11] + this.m[15] * other.m[15];
     };
 
     BABYLON.Matrix.prototype.equals = function (value) {
@@ -1111,7 +1148,7 @@
                 this.m[8] === value.m[8] && this.m[9] === value.m[9] && this.m[10] === value.m[10] && this.m[11] === value.m[11] &&
                 this.m[12] === value.m[12] && this.m[13] === value.m[13] && this.m[14] === value.m[14] && this.m[15] === value.m[15]);
     };
-    
+
     BABYLON.Matrix.prototype.clone = function () {
         return BABYLON.Matrix.FromValues(this.m[0], this.m[1], this.m[2], this.m[3],
             this.m[4], this.m[5], this.m[6], this.m[7],
@@ -1120,6 +1157,24 @@
     };
 
     // Statics
+    BABYLON.Matrix.FromArray = function (array, offset) {
+        var result = new BABYLON.Matrix();
+
+        BABYLON.Matrix.FromArrayToRef(array, offset, result);
+
+        return result;
+    };
+
+    BABYLON.Matrix.FromArrayToRef = function (array, offset, result) {
+        if (!offset) {
+            offset = 0;
+        }
+
+        for (var index = 0; index < 16; index++) {
+            result.m[index] = array[index + offset];
+        }
+    };
+
     BABYLON.Matrix.FromValuesToRef = function (initialM11, initialM12, initialM13, initialM14,
         initialM21, initialM22, initialM23, initialM24,
         initialM31, initialM32, initialM33, initialM34,
@@ -1142,14 +1197,14 @@
         result.m[14] = initialM43;
         result.m[15] = initialM44;
     };
-    
+
     BABYLON.Matrix.FromValues = function (initialM11, initialM12, initialM13, initialM14,
         initialM21, initialM22, initialM23, initialM24,
         initialM31, initialM32, initialM33, initialM34,
         initialM41, initialM42, initialM43, initialM44) {
 
         var result = new BABYLON.Matrix();
-        
+
         result.m[0] = initialM11;
         result.m[1] = initialM12;
         result.m[2] = initialM13;
@@ -1176,7 +1231,7 @@
             0, 0, 1.0, 0,
             0, 0, 0, 1.0);
     };
-    
+
     BABYLON.Matrix.IdentityToRef = function (result) {
         BABYLON.Matrix.FromValuesToRef(1.0, 0, 0, 0,
             0, 1.0, 0, 0,
@@ -1198,8 +1253,8 @@
 
         return result;
     };
-    
-    BABYLON.Matrix.RotationXToRef = function (angle, result) {        
+
+    BABYLON.Matrix.RotationXToRef = function (angle, result) {
         var s = Math.sin(angle);
         var c = Math.cos(angle);
 
@@ -1254,7 +1309,7 @@
         result.m[13] = 0;
         result.m[14] = 0;
     };
-    
+
     BABYLON.Matrix.RotationZ = function (angle) {
         var result = new BABYLON.Matrix();
 
@@ -1274,7 +1329,7 @@
         result.m[1] = s;
         result.m[4] = -s;
         result.m[5] = c;
-        
+
         result.m[2] = 0;
         result.m[3] = 0;
         result.m[6] = 0;
@@ -1322,7 +1377,7 @@
 
         return result;
     };
-    
+
     var tempQuaternion = new BABYLON.Quaternion(); // For RotationYawPitchRoll
     BABYLON.Matrix.RotationYawPitchRollToRef = function (yaw, pitch, roll, result) {
         BABYLON.Quaternion.RotationYawPitchRollToRef(yaw, pitch, roll, tempQuaternion);
@@ -1337,7 +1392,7 @@
 
         return result;
     };
-    
+
     BABYLON.Matrix.ScalingToRef = function (x, y, z, result) {
         result.m[0] = x;
         result.m[1] = 0;
@@ -1364,7 +1419,7 @@
 
         return result;
     };
-    
+
     BABYLON.Matrix.TranslationToRef = function (x, y, z, result) {
         BABYLON.Matrix.FromValuesToRef(1.0, 0, 0, 0,
             0, 1.0, 0, 0,
@@ -1428,7 +1483,7 @@
 
         return matrix;
     };
-    
+
     BABYLON.Matrix.OrthoOffCenterLHToRef = function (left, right, bottom, top, znear, zfar, result) {
         result.m[0] = 2.0 / (right - left);
         result.m[1] = result.m[2] = result.m[3] = 0;
@@ -1462,10 +1517,10 @@
         var matrix = BABYLON.Matrix.Zero();
 
         BABYLON.Matrix.PerspectiveFovLHToRef(fov, aspect, znear, zfar, matrix);
-        
+
         return matrix;
     };
-    
+
     BABYLON.Matrix.PerspectiveFovLHToRef = function (fov, aspect, znear, zfar, result) {
         var tan = 1.0 / (Math.tan(fov * 0.5));
 
@@ -1534,7 +1589,7 @@
 
         return matrix;
     };
-    
+
     BABYLON.Matrix.ReflectionToRef = function (plane, result) {
         plane.normalize();
         var x = plane.normal.x;
@@ -1566,7 +1621,7 @@
         this.normal = new BABYLON.Vector3(a, b, c);
         this.d = d;
     };
-    
+
     // Methods
     BABYLON.Plane.prototype.normalize = function () {
         var norm = (Math.sqrt((this.normal.x * this.normal.x) + (this.normal.y * this.normal.y) + (this.normal.z * this.normal.z)));
@@ -1582,14 +1637,14 @@
 
         this.d *= magnitude;
     };
-    
-    BABYLON.Plane.prototype.transform = function(transformation) {
+
+    BABYLON.Plane.prototype.transform = function (transformation) {
         var transposedMatrix = BABYLON.Matrix.Transpose(transformation);
         var x = this.normal.x;
         var y = this.normal.y;
         var z = this.normal.z;
         var d = this.d;
-        
+
         var normalX = (((x * transposedMatrix.m[0]) + (y * transposedMatrix.m[1])) + (z * transposedMatrix.m[2])) + (d * transposedMatrix.m[3]);
         var normalY = (((x * transposedMatrix.m[4]) + (y * transposedMatrix.m[5])) + (z * transposedMatrix.m[6])) + (d * transposedMatrix.m[7]);
         var normalZ = (((x * transposedMatrix.m[8]) + (y * transposedMatrix.m[9])) + (z * transposedMatrix.m[10])) + (d * transposedMatrix.m[11]);
@@ -1602,7 +1657,7 @@
     BABYLON.Plane.prototype.dotCoordinate = function (point) {
         return ((((this.normal.x * point.x) + (this.normal.y * point.y)) + (this.normal.z * point.z)) + this.d);
     };
-    
+
     BABYLON.Plane.prototype.copyFromPoints = function (point1, point2, point3) {
         var x1 = point2.x - point1.x;
         var y1 = point2.y - point1.y;
@@ -1626,7 +1681,7 @@
         this.normal.z = xy * invPyth;
         this.d = -((this.normal.x * point1.x) + (this.normal.y * point1.y) + (this.normal.z * point1.z));
     };
-    
+
     BABYLON.Plane.prototype.isFrontFacingTo = function (direction, epsilon) {
         var dot = BABYLON.Vector3.Dot(this.normal, direction);
 
@@ -1642,14 +1697,14 @@
         return new BABYLON.Plane(array[0], array[1], array[2], array[3]);
     };
 
-    BABYLON.Plane.FromPoints = function(point1, point2, point3) {
+    BABYLON.Plane.FromPoints = function (point1, point2, point3) {
         var result = new BABYLON.Plane(0, 0, 0, 0);
 
         result.copyFromPoints(point1, point2, point3);
 
         return result;
     };
-    
+
     BABYLON.Plane.FromPositionAndNormal = function (origin, normal) {
         var result = new BABYLON.Plane(0, 0, 0, 0);
         normal.normalize();
@@ -1671,7 +1726,7 @@
     // Statics
     BABYLON.Frustum.GetPlanes = function (transform) {
         var frustumPlanes = [];
-        
+
         for (var index = 0; index < 6; index++) {
             frustumPlanes.push(new BABYLON.Plane(0, 0, 0, 0));
         }
@@ -1680,7 +1735,7 @@
 
         return frustumPlanes;
     };
-    
+
     BABYLON.Frustum.GetPlanesToRef = function (transform, frustumPlanes) {
         // Near
         frustumPlanes[0].normal.x = transform.m[3] + transform.m[2];
@@ -1688,14 +1743,14 @@
         frustumPlanes[0].normal.z = transform.m[10] + transform.m[10];
         frustumPlanes[0].d = transform.m[15] + transform.m[14];
         frustumPlanes[0].normalize();
-        
+
         // Far
         frustumPlanes[1].normal.x = transform.m[3] - transform.m[2];
         frustumPlanes[1].normal.y = transform.m[7] - transform.m[6];
         frustumPlanes[1].normal.z = transform.m[11] - transform.m[10];
         frustumPlanes[1].d = transform.m[15] - transform.m[14];
         frustumPlanes[1].normalize();
-        
+
         // Left
         frustumPlanes[2].normal.x = transform.m[3] + transform.m[0];
         frustumPlanes[2].normal.y = transform.m[7] + transform.m[4];

+ 112 - 21
Babylon/Tools/babylon.sceneLoader.js

@@ -50,7 +50,7 @@
 
         texture.wrapU = parsedTexture.wrapU;
         texture.wrapV = parsedTexture.wrapV;
-        
+
         // Animations
         if (parsedTexture.animations) {
             for (var animationIndex = 0; animationIndex < parsedTexture.animations.length; animationIndex++) {
@@ -63,6 +63,27 @@
         return texture;
     };
 
+    var parseSkeleton = function (parsedSkeleton, scene) {
+        var skeleton = new BABYLON.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(parseAnimation(parsedBone.animation));
+            }
+        }
+
+        return skeleton;
+    };
+
     var parseMaterial = function (parsedMaterial, scene, rootUrl) {
         var material;
         material = new BABYLON.StandardMaterial(parsedMaterial.name, scene);
@@ -93,15 +114,15 @@
         if (parsedMaterial.reflectionTexture) {
             material.reflectionTexture = loadTexture(rootUrl, parsedMaterial.reflectionTexture, scene);
         }
-        
+
         if (parsedMaterial.emissiveTexture) {
             material.emissiveTexture = loadTexture(rootUrl, parsedMaterial.emissiveTexture, scene);
         }
-        
+
         if (parsedMaterial.specularTexture) {
             material.specularTexture = loadTexture(rootUrl, parsedMaterial.specularTexture, scene);
         }
-        
+
         if (parsedMaterial.bumpTexture) {
             material.bumpTexture = loadTexture(rootUrl, parsedMaterial.bumpTexture, scene);
         }
@@ -137,7 +158,7 @@
 
         return multiMaterial;
     };
-    
+
     var parseParticleSystem = function (parsedParticleSystem, scene, rootUrl) {
         var emitter = scene.getLastMeshByID(parsedParticleSystem.emitterId);
 
@@ -169,7 +190,7 @@
 
         return particleSystem;
     };
-    
+
     var parseShadowGenerator = function (parsedShadowGenerator, scene) {
         var light = scene.getLightByID(parsedShadowGenerator.lightId);
         var shadowGenerator = new BABYLON.ShadowGenerator(parsedShadowGenerator.mapSize, light);
@@ -202,6 +223,9 @@
                 case BABYLON.Animation.ANIMATIONTYPE_QUATERNION:
                     data = BABYLON.Quaternion.FromArray(key.values);
                     break;
+                case BABYLON.Animation.ANIMATIONTYPE_MATRIX:
+                    data = BABYLON.Matrix.FromArray(key.values);
+                    break;
                 case BABYLON.Animation.ANIMATIONTYPE_VECTOR3:
                 default:
                     data = BABYLON.Vector3.FromArray(key.values);
@@ -219,7 +243,7 @@
         return animation;
     };
 
-    var parseLight = function(parsedLight, scene) {
+    var parseLight = function (parsedLight, scene) {
         var light;
 
         switch (parsedLight.type) {
@@ -255,6 +279,10 @@
         mesh.position = BABYLON.Vector3.FromArray(parsedMesh.position);
         mesh.rotation = BABYLON.Vector3.FromArray(parsedMesh.rotation);
         mesh.scaling = BABYLON.Vector3.FromArray(parsedMesh.scaling);
+        
+        if (parsedMesh.localMatrix) {
+            mesh.setPivotMatrix(BABYLON.Matrix.FromArray(parsedMesh.localMatrix));
+        }
 
         mesh.setEnabled(parsedMesh.isEnabled);
         mesh.isVisible = parsedMesh.isVisible;
@@ -272,31 +300,58 @@
         if (parsedMesh.positions && parsedMesh.normals && parsedMesh.indices) {
             mesh.setVerticesData(parsedMesh.positions, BABYLON.VertexBuffer.PositionKind, false);
             mesh.setVerticesData(parsedMesh.normals, BABYLON.VertexBuffer.NormalKind, false);
-            
+
             if (parsedMesh.uvs) {
                 mesh.setVerticesData(parsedMesh.uvs, BABYLON.VertexBuffer.UVKind, false);
             }
-            
+
             if (parsedMesh.uvs2) {
                 mesh.setVerticesData(parsedMesh.uvs2, BABYLON.VertexBuffer.UV2Kind, false);
             }
-            
+
             if (parsedMesh.colors) {
                 mesh.setVerticesData(parsedMesh.colors, BABYLON.VertexBuffer.ColorKind, false);
             }
 
+            if (parsedMesh.matricesIndices) {
+                var floatIndices = [];
+
+                for (var i = 0; i < parsedMesh.matricesIndices.length; i++) {
+                    var matricesIndex = parsedMesh.matricesIndices[i];
+
+                    floatIndices.push(matricesIndex & 0x000000FF);
+                    floatIndices.push((matricesIndex & 0x0000FF00) >> 8);
+                    floatIndices.push((matricesIndex & 0x00FF0000) >> 16);
+                    floatIndices.push(matricesIndex >> 24);
+                }
+
+                mesh.setVerticesData(floatIndices, BABYLON.VertexBuffer.MatricesIndicesKind, false);
+            }
+
+            if (parsedMesh.matricesWeights) {
+                mesh.setVerticesData(parsedMesh.matricesWeights, BABYLON.VertexBuffer.MatricesWeightsKind, false);
+            }
+
             mesh.setIndices(parsedMesh.indices);
         }
 
+        // Parent
         if (parsedMesh.parentId) {
             mesh.parent = scene.getLastMeshByID(parsedMesh.parentId);
         }
+
+        // Material
         if (parsedMesh.materialId) {
             mesh.setMaterialByID(parsedMesh.materialId);
         } else {
             mesh.material = null;
         }
 
+        // Skeleton
+        if (parsedMesh.skeletonId > -1) {
+            mesh.skeleton = scene.getLastSkeletonByID(parsedMesh.skeletonId);
+        }
+
         // SubMeshes
         if (parsedMesh.subMeshes) {
             mesh.subMeshes = [];
@@ -306,7 +361,7 @@
                 var subMesh = new BABYLON.SubMesh(parsedSubMesh.materialIndex, parsedSubMesh.verticesStart, parsedSubMesh.verticesCount, parsedSubMesh.indexStart, parsedSubMesh.indexCount, mesh);
             }
         }
-        
+
         // Animations
         if (parsedMesh.animations) {
             for (var animationIndex = 0; animationIndex < parsedMesh.animations.length; animationIndex++) {
@@ -315,7 +370,7 @@
                 mesh.animations.push(parseAnimation(parsedAnimation));
             }
         }
-        
+
         if (parsedMesh.autoAnimate) {
             scene.beginAnimation(mesh, parsedMesh.autoAnimateFrom, parsedMesh.autoAnimateTo, parsedMesh.autoAnimateLoop, 1.0);
         }
@@ -328,7 +383,7 @@
             hierarchyIds.push(mesh.id);
             return true;
         }
-        
+
         if (mesh.parentId && hierarchyIds.indexOf(mesh.parentId) !== -1) {
             hierarchyIds.push(mesh.id);
             return true;
@@ -339,31 +394,38 @@
 
     BABYLON.SceneLoader = {
         ImportMesh: function (meshName, rootUrl, sceneFilename, scene, then, progressCallBack) {
+            // Checking if a manifest file has been set for this scene and if offline mode has been requested
+            BABYLON.Database.CheckManifestFile(rootUrl, sceneFilename);
+
             BABYLON.Tools.LoadFile(rootUrl + sceneFilename, function (data) {
                 var parsedData = JSON.parse(data);
 
                 // Meshes
                 var meshes = [];
                 var particleSystems = [];
-                var hierarchyIds = [];                
+                var skeletons = [];
+                var loadedSkeletonsIds = [];
+                var loadedMaterialsIds = [];
+                var hierarchyIds = [];
                 for (var index = 0; index < parsedData.meshes.length; index++) {
                     var parsedMesh = parsedData.meshes[index];
 
                     if (!meshName || isDescendantOf(parsedMesh, meshName, hierarchyIds)) {
                         // Material ?
                         if (parsedMesh.materialId) {
-                            var materialFound = (scene.getMaterialByID(parsedMesh.materialId) !== null);
-                            
+                            var materialFound = (loadedMaterialsIds.indexOf(parsedMesh.materialId) !== -1);
+
                             if (!materialFound) {
                                 for (var multimatIndex = 0; multimatIndex < parsedData.multiMaterials.length; multimatIndex++) {
                                     var parsedMultiMaterial = parsedData.multiMaterials[multimatIndex];
                                     if (parsedMultiMaterial.id == parsedMesh.materialId) {
                                         for (var matIndex = 0; matIndex < parsedMultiMaterial.materials.length; matIndex++) {
                                             var subMatId = parsedMultiMaterial.materials[matIndex];
-
+                                            loadedMaterialsIds.push(subMatId);
                                             parseMaterialById(subMatId, parsedData, scene, rootUrl);
                                         }
 
+                                        loadedMaterialsIds.push(parsedMultiMaterial.id);
                                         parseMultiMaterial(parsedMultiMaterial, scene);
                                         materialFound = true;
                                         break;
@@ -372,14 +434,32 @@
                             }
 
                             if (!materialFound) {
+                                loadedMaterialsIds.push(parsedMesh.materialId);
                                 parseMaterialById(parsedMesh.materialId, parsedData, scene, rootUrl);
                             }
                         }
 
-                        meshes.push(parseMesh(parsedMesh, scene));
+                        // Skeleton ?
+                        if (parsedMesh.skeletonId > -1 && scene.skeletons) {
+                            var skeletonAlreadyLoaded = (loadedSkeletonsIds.indexOf(parsedMesh.skeletonId) > -1);
+
+                            if (!skeletonAlreadyLoaded) {
+                                for (var skeletonIndex = 0; skeletonIndex < parsedData.skeletons.length; skeletonIndex++) {
+                                    var parsedSkeleton = parsedData.skeletons[skeletonIndex];
+
+                                    if (parsedSkeleton.id === parsedMesh.skeletonId) {
+                                        skeletons.push(parseSkeleton(parsedSkeleton, scene));
+                                        loadedSkeletonsIds.push(parsedSkeleton.id);
+                                    }
+                                }
+                            }
+                        }
+
+                        var mesh = parseMesh(parsedMesh, scene);
+                        meshes.push(mesh);
                     }
                 }
-                
+
                 // Particles
                 if (parsedData.particleSystems) {
                     for (var index = 0; index < parsedData.particleSystems.length; index++) {
@@ -392,11 +472,14 @@
                 }
 
                 if (then) {
-                    then(meshes, particleSystems);
+                    then(meshes, particleSystems, skeletons);
                 }
             }, progressCallBack);
         },
         Load: function (rootUrl, sceneFilename, engine, then, progressCallBack) {
+            // Checking if a manifest file has been set for this scene and if offline mode has been requested
+            BABYLON.Database.CheckManifestFile(rootUrl, sceneFilename);
+            
             BABYLON.Tools.LoadFile(rootUrl + sceneFilename, function (data) {
                 var parsedData = JSON.parse(data);
                 var scene = new BABYLON.Scene(engine);
@@ -467,6 +550,14 @@
                     }
                 }
 
+                // Skeletons
+                if (parsedData.skeletons) {
+                    for (var index = 0; index < parsedData.skeletons.length; index++) {
+                        var parsedSkeleton = parsedData.skeletons[index];
+                        parseSkeleton(parsedSkeleton, scene);
+                    }
+                }
+
                 // Meshes
                 for (var index = 0; index < parsedData.meshes.length; index++) {
                     var parsedMesh = parsedData.meshes[index];
@@ -480,7 +571,7 @@
                         parseParticleSystem(parsedParticleSystem, scene, rootUrl);
                     }
                 }
-                
+
                 // Shadows
                 if (parsedData.shadowGenerators) {
                     for (var index = 0; index < parsedData.shadowGenerators.length; index++) {

+ 69 - 15
Babylon/Tools/babylon.tools.js

@@ -17,6 +17,13 @@
         }
     };
 
+    BABYLON.Tools.SmartArray.prototype.pushNoDuplicate = function(value) {
+        if (this.indexOf(value) > -1) {
+            return;
+        }
+        this.push(value);
+    };
+
     BABYLON.Tools.SmartArray.prototype.reset = function() {
         this.length = 0;
     };
@@ -118,28 +125,75 @@
 
     // External files
     BABYLON.Tools.BaseUrl = "";
-    
+
+    BABYLON.Tools.LoadImage = function (url, onload, onerror) {  
+        var img = new Image();
+
+        img.onload = function () {
+            onload(img);
+        };
+
+        img.onerror = function (err) {
+            onerror(img, err);
+        };
+
+        var noIndexedDB = function () {
+            img.src = url;
+        };
+
+        var loadFromIndexedDB = function () {
+            BABYLON.Database.LoadImageFromDB(url, img);
+        };
+
+        if (BABYLON.Database.enableTexturesOffline && BABYLON.Database.isUASupportingBlobStorage) {
+            BABYLON.Database.OpenAsync(loadFromIndexedDB, noIndexedDB);
+        }
+        else {
+            noIndexedDB();
+        }
+
+        return img;
+    };
+
     BABYLON.Tools.LoadFile = function (url, callback, progressCallBack) {
-        var request = new XMLHttpRequest();
-        var loadUrl = BABYLON.Tools.BaseUrl + url;
-        request.open('GET', loadUrl, true);
-
-        request.onprogress = progressCallBack;
-
-        request.onreadystatechange = function () {
-            if (request.readyState == 4) {
-                if (request.status == 200) {
-                    callback(request.responseText);
-                } else { // Failed
-                    throw new Error(request.status, "Unable to load " + loadUrl);
+        var noIndexedDB = function () {
+            var request = new XMLHttpRequest();
+            var loadUrl = BABYLON.Tools.BaseUrl + url;
+            request.open('GET', loadUrl, true);
+
+            request.onprogress = progressCallBack;
+
+            request.onreadystatechange = function () {
+                if (request.readyState == 4) {
+                    if (request.status == 200) {
+                        callback(request.responseText);
+                    } else { // Failed
+                        throw new Error(request.status, "Unable to load " + loadUrl);
+                    }
                 }
-            }
+            };
+
+            request.send(null);
         };
 
-        request.send(null);
+        var loadFromIndexedDB = function () {
+            BABYLON.Database.LoadSceneFromDB(callback, progressCallBack);
+        };
+
+        // Caching only scenes files
+        if (url.indexOf(".babylon") !== -1 && (BABYLON.Database.enableSceneOffline)) {
+            BABYLON.Database.OpenAsync(loadFromIndexedDB, noIndexedDB);
+        }
+        else {
+            noIndexedDB();
+        }
     };
 
     // Misc.    
+    BABYLON.Tools.isIE = function () {
+        return window.ActiveXObject !== undefined;
+    };
+    
     BABYLON.Tools.WithinEpsilon = function (a, b) {
         var num = a - b;
         return -1.401298E-45 <= num && num <= 1.401298E-45;

+ 61 - 41
Babylon/babylon.engine.js

@@ -11,7 +11,7 @@
             throw new Error("WebGL not supported");
         }
 
-        if (this._gl === undefined || this._gl === null) {
+        if (!this._gl) {
             throw new Error("WebGL not supported");
         }
 
@@ -68,7 +68,7 @@
             } else if (document.msIsFullScreen !== undefined) {
                 that.isFullscreen = document.msIsFullScreen;
             }
-            
+
             // Pointer lock
             if (that.isFullscreen && that._pointerLockRequested) {
                 canvas.requestPointerLock = canvas.requestPointerLock ||
@@ -86,7 +86,7 @@
         document.addEventListener("mozfullscreenchange", onFullscreenChange, false);
         document.addEventListener("webkitfullscreenchange", onFullscreenChange, false);
         document.addEventListener("msfullscreenchange", onFullscreenChange, false);
-        
+
         // Pointer lock
         this.isPointerLock = false;
 
@@ -143,7 +143,7 @@
         this._renderFunction = null;
         this._runningLoop = false;
     };
-    
+
     BABYLON.Engine.prototype._renderLoop = function () {
         // Start new frame
         this.beginFrame();
@@ -170,7 +170,7 @@
         this._renderFunction = renderFunction;
 
         var that = this;
-        BABYLON.Tools.QueueNewFrame(function() {
+        BABYLON.Tools.QueueNewFrame(function () {
             that._renderLoop();
         });
     };
@@ -263,6 +263,7 @@
 
     BABYLON.Engine.prototype.updateDynamicVertexBuffer = function (vertexBuffer, vertices) {
         this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vertexBuffer);
+        // Should be (vertices instanceof Float32Array ? vertices : new Float32Array(vertices)) but Chrome raises an Exception in this case :(
         this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
         this._gl.bindBuffer(this._gl.ARRAY_BUFFER, null);
     };
@@ -277,17 +278,21 @@
     };
 
     BABYLON.Engine.prototype.bindBuffers = function (vertexBuffer, indexBuffer, vertexDeclaration, vertexStrideSize, effect) {
-        this._cachedVertexBuffers = null;
-        this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vertexBuffer);
+        if (this._cachedVertexBuffers !== vertexBuffer || this._cachedEffectForVertexBuffers !== effect) {
+            this._cachedVertexBuffers = vertexBuffer;
+            this._cachedEffectForVertexBuffers = effect;
 
-        var offset = 0;
-        for (var index = 0; index < vertexDeclaration.length; index++) {
-            var order = effect.getAttribute(index);
+            this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vertexBuffer);
 
-            if (order >= 0) {
-                this._gl.vertexAttribPointer(order, vertexDeclaration[index], this._gl.FLOAT, false, vertexStrideSize, offset);
+            var offset = 0;
+            for (var index = 0; index < vertexDeclaration.length; index++) {
+                var order = effect.getAttribute(index);
+
+                if (order >= 0) {
+                    this._gl.vertexAttribPointer(order, vertexDeclaration[index], this._gl.FLOAT, false, vertexStrideSize, offset);
+                }
+                offset += vertexDeclaration[index] * 4;
             }
-            offset += vertexDeclaration[index] * 4;
         }
 
         if (this._cachedIndexBuffer !== indexBuffer) {
@@ -295,11 +300,12 @@
             this._gl.bindBuffer(this._gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
         }
     };
-    
+
     BABYLON.Engine.prototype.bindMultiBuffers = function (vertexBuffers, indexBuffer, effect) {
-        if (this._cachedVertexBuffers !== vertexBuffers) {
+        if (this._cachedVertexBuffers !== vertexBuffers || this._cachedEffectForVertexBuffers !== effect) {
             this._cachedVertexBuffers = vertexBuffers;
-            
+            this._cachedEffectForVertexBuffers = effect;
+
             var attributes = effect.getAttributesNames();
 
             for (var index = 0; index < attributes.length; index++) {
@@ -371,7 +377,7 @@
         if (error) {
             throw new Error(error);
         }
-        
+
         this._gl.deleteShader(vertexShader);
         this._gl.deleteShader(fragmentShader);
 
@@ -421,6 +427,13 @@
         this._currentEffect = effect;
     };
 
+    BABYLON.Engine.prototype.setMatrices = function (uniform, matrices) {
+        if (!uniform)
+            return;
+
+        this._gl.uniformMatrix4fv(uniform, false, matrices);
+    };
+
     BABYLON.Engine.prototype.setMatrix = function (uniform, matrix) {
         if (!uniform)
             return;
@@ -550,9 +563,10 @@
         this._currentState = {
             culling: null
         };
-        
+
         this._cachedVertexBuffers = null;
         this._cachedVertexBuffers = null;
+        _cachedEffectForVertexBuffers = null;
     };
 
     var getExponantOfTwo = function (value, max) {
@@ -571,17 +585,22 @@
     BABYLON.Engine.prototype.createTexture = function (url, noMipmap, invertY, scene) {
         var texture = this._gl.createTexture();
         var that = this;
-        var img = new Image();
-
-        img.onload = function () {
-            that._workingCanvas.width = getExponantOfTwo(img.width, that._caps.maxTextureSize);
-            that._workingCanvas.height = getExponantOfTwo(img.height, that._caps.maxTextureSize);
+        
+        var onload = function (img) {
+            var potWidth = getExponantOfTwo(img.width, that._caps.maxTextureSize);
+            var potHeight = getExponantOfTwo(img.height, that._caps.maxTextureSize);
+            var isPot = (img.width == potWidth && img.height == potHeight);
 
-            that._workingContext.drawImage(img, 0, 0, img.width, img.height, 0, 0, that._workingCanvas.width, that._workingCanvas.height);
+            if (!isPot) {
+                that._workingCanvas.width = potWidth;
+                that._workingCanvas.height = potHeight;
 
+                that._workingContext.drawImage(img, 0, 0, img.width, img.height, 0, 0, potWidth, potHeight);
+            };
+            
             that._gl.bindTexture(that._gl.TEXTURE_2D, texture);
             that._gl.pixelStorei(that._gl.UNPACK_FLIP_Y_WEBGL, invertY === undefined ? true : invertY);
-            that._gl.texImage2D(that._gl.TEXTURE_2D, 0, that._gl.RGBA, that._gl.RGBA, that._gl.UNSIGNED_BYTE, that._workingCanvas);
+            that._gl.texImage2D(that._gl.TEXTURE_2D, 0, that._gl.RGBA, that._gl.RGBA, that._gl.UNSIGNED_BYTE, isPot ? img : that._workingCanvas);
             that._gl.texParameteri(that._gl.TEXTURE_2D, that._gl.TEXTURE_MAG_FILTER, that._gl.LINEAR);
 
             if (noMipmap) {
@@ -595,18 +614,18 @@
             that._activeTexturesCache = [];
             texture._baseWidth = img.width;
             texture._baseHeight = img.height;
-            texture._width = that._workingCanvas.width;
-            texture._height = that._workingCanvas.height;
+            texture._width = potWidth;
+            texture._height = potHeight;
             texture.isReady = true;
-            scene._removePendingData(img);
+            scene._removePendingData(texture);
         };
 
-        img.onerror = function () {
-            scene._removePendingData(img);
+        var onerror = function () {
+            scene._removePendingData(texture);
         };
 
-        scene._addPendingData(img);
-        img.src = url;
+        scene._addPendingData(texture);
+        BABYLON.Tools.LoadImage(url, onload, onerror);
 
         texture.url = url;
         texture.noMipmap = noMipmap;
@@ -677,11 +696,11 @@
         } else {
             this._gl.texImage2D(this._gl.TEXTURE_2D, 0, this._gl.RGBA, this._gl.RGBA, this._gl.UNSIGNED_BYTE, video);
         }
-        
+
         if (texture.generateMipMaps) {
             this._gl.generateMipmap(this._gl.TEXTURE_2D);
         }
-        
+
         this._gl.bindTexture(this._gl.TEXTURE_2D, null);
         this._activeTexturesCache = [];
         texture.isReady = true;
@@ -731,9 +750,10 @@
     var extensions = ["_px.jpg", "_py.jpg", "_pz.jpg", "_nx.jpg", "_ny.jpg", "_nz.jpg"];
 
     var cascadeLoad = function (rootUrl, index, loadedImages, scene, onfinish) {
-        var img = new Image();
-        img.onload = function () {
-            loadedImages.push(this);
+        var img;
+        
+        var onload = function () {
+            loadedImages.push(img);
 
             scene._removePendingData(img);
 
@@ -744,12 +764,12 @@
             }
         };
 
-        img.onerrror = function () {
+        var onerror = function () {
             scene._removePendingData(img);
         };
-
+        
+        img = BABYLON.Tools.LoadImage(rootUrl + extensions[index], onload, onerror);
         scene._addPendingData(img);
-        img.src = rootUrl + extensions[index];
     };
 
     BABYLON.Engine.prototype.createCubeTexture = function (rootUrl, scene) {
@@ -937,4 +957,4 @@
             return false;
         }
     };
-})();
+})();

+ 102 - 31
Babylon/babylon.scene.js

@@ -26,6 +26,8 @@
 
         this._onBeforeRenderCallbacks = [];
 
+        this._mustCheckIsReady = false;
+
         // Fog
         this.fogMode = BABYLON.Scene.FOGMODE_NONE;
         this.fogColor = new BABYLON.Color3(0.2, 0.2, 0.3);
@@ -51,6 +53,7 @@
         this._processedMaterials = new BABYLON.Tools.SmartArray(256);
         this._renderTargets = new BABYLON.Tools.SmartArray(256);
         this._activeParticleSystems = new BABYLON.Tools.SmartArray(256);
+        this._activeSkeletons = new BABYLON.Tools.SmartArray(32);
 
         // Materials
         this.materials = [];
@@ -69,10 +72,13 @@
 
         // Layers
         this.layers = [];
+        
+        // Skeletons
+        this.skeletons = [];
 
         // Collisions
         this.collisionsEnabled = true;
-        this.gravity = new BABYLON.Vector3(0, 0, -9);
+        this.gravity = new BABYLON.Vector3(0, -9.0, 0);
 
         // Animations
         this._activeAnimatables = [];
@@ -83,6 +89,9 @@
         // Internals
         this._scaledPosition = BABYLON.Vector3.Zero();
         this._scaledVelocity = BABYLON.Vector3.Zero();
+
+        // Postprocesses
+        this.postProcessManager = new BABYLON.PostProcessManager();
     };
 
     // Properties   
@@ -141,8 +150,10 @@
 
     // Ready
     BABYLON.Scene.prototype.isReady = function () {
-        for (var index = 0; index < this.materials.length; index++) {
-            if (!this.materials[index].isReady()) {
+        for (var index = 0; index < this.meshes.length; index++) {
+            var mesh = this.meshes[index]; 
+            var mat = mesh.material;
+            if (mat && !mat.isReady(mesh)) {
                 return false;
             }
         }
@@ -190,11 +201,7 @@
             this._pendingData.splice(index, 1);
 
             if (this._pendingData.length === 0) {
-                this._onReadyCallbacks.forEach(function (func) {
-                    func();
-                });
-
-                this._onReadyCallbacks = [];
+                this._mustCheckIsReady = true;
             }
         }
     };
@@ -231,10 +238,17 @@
             }
         }
     };
-
+    
     BABYLON.Scene.prototype._animate = function () {
+        if (!this._animationStartDate) {
+            this._animationStartDate = new Date();
+        }
+        // Getting time
+        var now = new Date();
+        var delay = now - this._animationStartDate;
+        
         for (var index = 0; index < this._activeAnimatables.length; index++) {
-            if (!this._activeAnimatables[index]._animate()) {
+            if (!this._activeAnimatables[index]._animate(delay)) {
                 this._activeAnimatables.splice(index, 1);
                 index--;
             }
@@ -264,7 +278,7 @@
     // Methods
     BABYLON.Scene.prototype.activeCameraByID = function (id) {
         for (var index = 0; index < this.cameras.length; index++) {
-            if (this.cameras[index].id == id) {
+            if (this.cameras[index].id === id) {
                 this.activeCamera = this.cameras[index];
                 return;
             }
@@ -273,7 +287,7 @@
 
     BABYLON.Scene.prototype.getMaterialByID = function (id) {
         for (var index = 0; index < this.materials.length; index++) {
-            if (this.materials[index].id == id) {
+            if (this.materials[index].id === id) {
                 return this.materials[index];
             }
         }
@@ -283,7 +297,7 @@
 
     BABYLON.Scene.prototype.getLightByID = function (id) {
         for (var index = 0; index < this.lights.length; index++) {
-            if (this.lights[index].id == id) {
+            if (this.lights[index].id === id) {
                 return this.lights[index];
             }
         }
@@ -293,7 +307,7 @@
 
     BABYLON.Scene.prototype.getMeshByID = function (id) {
         for (var index = 0; index < this.meshes.length; index++) {
-            if (this.meshes[index].id == id) {
+            if (this.meshes[index].id === id) {
                 return this.meshes[index];
             }
         }
@@ -302,25 +316,54 @@
     };
 
     BABYLON.Scene.prototype.getLastMeshByID = function (id) {
-        var result = null;
-        for (var index = 0; index < this.meshes.length; index++) {
-            if (this.meshes[index].id == id) {
-                result = this.meshes[index];
+        for (var index = this.meshes.length - 1; index >= 0 ; index--) {
+            if (this.meshes[index].id === id) {
+                return this.meshes[index];
             }
         }
 
-        return result;
+        return null;
     };
 
     BABYLON.Scene.prototype.getMeshByName = function (name) {
         for (var index = 0; index < this.meshes.length; index++) {
-            if (this.meshes[index].name == name) {
+            if (this.meshes[index].name === name) {
                 return this.meshes[index];
             }
         }
 
         return null;
     };
+    
+    BABYLON.Scene.prototype.getLastSkeletonByID = function (id) {
+        for (var index = this.skeletons.length - 1; index >= 0 ; index--) {
+            if (this.skeletons[index].id === id) {
+                return this.skeletons[index];
+            }
+        }
+
+        return null;
+    };
+    
+    BABYLON.Scene.prototype.getSkeletonById = function (id) {
+        for (var index = 0; index < this.skeletons.length; index++) {
+            if (this.skeletons[index].id === id) {
+                return this.skeletons[index];
+            }
+        }
+
+        return null;
+    };
+    
+    BABYLON.Scene.prototype.getSkeletonByName = function (name) {
+        for (var index = 0; index < this.skeleton.length; index++) {
+            if (this.skeletons[index].name === name) {
+                return this.skeletons[index];
+            }
+        }
+
+        return null;
+    };
 
     BABYLON.Scene.prototype.isActiveMesh = function (mesh) {
         return (this._activeMeshes.indexOf(mesh) !== -1);
@@ -362,6 +405,7 @@
         this._processedMaterials.reset();
         this._renderTargets.reset();
         this._activeParticleSystems.reset();
+        this._activeSkeletons.reset();
 
         if (!this._frustumPlanes) {
             this._frustumPlanes = BABYLON.Frustum.GetPlanes(this._transformMatrix);
@@ -399,6 +443,10 @@
                         }
                         mesh._renderId = this._renderId;
 
+                        if (mesh.skeleton) {
+                            this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
+                        }
+
                         var subMeshes = block.subMeshes[meshIndex];
                         for (var subIndex = 0; subIndex < subMeshes.length; subIndex++) {
                             var subMesh = subMeshes[subIndex];
@@ -429,6 +477,10 @@
 
                 if (mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && mesh.isInFrustrum(this._frustumPlanes)) {
                     this._activeMeshes.push(mesh);
+                    
+                    if (mesh.skeleton) {
+                        this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
+                    }
 
                     for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
                         var subMesh = mesh.subMeshes[subIndex];
@@ -514,6 +566,18 @@
         this._particlesDuration = 0;
         this._activeParticles = 0;
         var engine = this._engine;
+        
+        if (this._mustCheckIsReady) {
+            if (this.isReady()) {
+                this._mustCheckIsReady = false;
+                this._onReadyCallbacks.forEach(function(func) {
+                    func();
+                });
+
+                this._onReadyCallbacks = [];
+                BABYLON.Database.Release();
+            }
+        }
 
         // Before render
         if (this.beforeRender) {
@@ -539,13 +603,20 @@
         var beforeEvaluateActiveMeshesDate = new Date();
         this._evaluateActiveMeshes();
         this._evaluateActiveMeshesDuration = new Date() - beforeEvaluateActiveMeshesDate;
+        
+        // Skeletons
+        for (var skeletonIndex = 0; skeletonIndex < this._activeSkeletons.length; skeletonIndex++) {
+            var skeleton = this._activeSkeletons.data[skeletonIndex];
+
+            skeleton.prepare();
+        }
 
         // Shadows
         for (var lightIndex = 0; lightIndex < this.lights.length; lightIndex++) {
             var light = this.lights[lightIndex];
             var shadowGenerator = light.getShadowGenerator();
 
-            if (light.isEnabled && shadowGenerator && shadowGenerator.isReady()) {
+            if (light.isEnabled && shadowGenerator) {
                 this._renderTargets.push(shadowGenerator.getShadowMap());
             }
         }
@@ -563,6 +634,9 @@
         }
         this._renderTargetsDuration = new Date() - beforeRenderTargetDate;
 
+        // Prepare Frame
+        this.postProcessManager._prepareFrame();
+
         // Clear
         var beforeRenderDate = new Date();
         engine.clear(this.clearColor, this.autoClear, true);
@@ -598,6 +672,9 @@
 
         this._renderDuration = new Date() - beforeRenderDate;
 
+        // Finalize frame
+        this.postProcessManager._finalizeFrame();
+
         // Update camera
         this.activeCamera._update();
 
@@ -621,6 +698,8 @@
         this.beforeRender = null;
         this.afterRender = null;
 
+        this.skeletons = [];
+
         // Detach cameras
         var canvas = this._engine.getRenderingCanvas();
         var index;
@@ -660,7 +739,7 @@
 
         // Release textures
         while (this.textures.length) {
-            this.textures[index].dispose();
+            this.textures[0].dispose();
         }
 
         // Remove from engine
@@ -797,15 +876,7 @@
 
             distance = result.distance;
             pickedMesh = mesh;
-
-            // Get picked point
-            var worldOrigin = BABYLON.Vector3.TransformCoordinates(ray.origin, world);
-            var direction = ray.direction.clone();
-            direction.normalize();
-            direction = direction.scale(result.distance);
-            var worldDirection = BABYLON.Vector3.TransformNormal(direction, world);
-
-            pickedPoint = worldOrigin.add(worldDirection);
+            pickedPoint = result.pickedPoint;
         }
 
         return { hit: distance != Number.MAX_VALUE, distance: distance, pickedMesh: pickedMesh, pickedPoint: pickedPoint };

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 908 - 709
Exporters/Blender/io_export_babylon.py


+ 6 - 0
Exporters/FBX - OBJ/BabylonExport/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<configuration>
+  <startup useLegacyV2RuntimeActivationPolicy="true"> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
+    </startup>
+</configuration>

+ 761 - 0
Exporters/FBX - OBJ/BabylonExport/BabylonExport.csproj

@@ -0,0 +1,761 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{1E0A8EB2-7022-42E2-8970-F0374188A09D}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>BabylonExport</RootNamespace>
+    <AssemblyName>BabylonExport</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SccProjectName>SAK</SccProjectName>
+    <SccLocalPath>SAK</SccLocalPath>
+    <SccAuxPath>SAK</SccAuxPath>
+    <SccProvider>SAK</SccProvider>
+    <TargetFrameworkProfile />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+    <RestorePackages>true</RestorePackages>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>x86</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.Build" />
+    <Reference Include="Microsoft.Build.Engine" />
+    <Reference Include="Microsoft.Build.Framework" />
+    <Reference Include="Microsoft.Xna.Framework">
+      <HintPath>..\Ref\XNA\Microsoft.Xna.Framework.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline">
+      <HintPath>..\Ref\XNA\Microsoft.Xna.Framework.Content.Pipeline.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline.AudioImporters">
+      <HintPath>..\Ref\XNA\Microsoft.Xna.Framework.Content.Pipeline.AudioImporters.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline.EffectImporter">
+      <HintPath>..\Ref\XNA\Microsoft.Xna.Framework.Content.Pipeline.EffectImporter.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline.FBXImporter">
+      <HintPath>..\Ref\XNA\Microsoft.Xna.Framework.Content.Pipeline.FBXImporter.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline.TextureImporter">
+      <HintPath>..\Ref\XNA\Microsoft.Xna.Framework.Content.Pipeline.TextureImporter.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline.VideoImporters">
+      <HintPath>..\Ref\XNA\Microsoft.Xna.Framework.Content.Pipeline.VideoImporters.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline.XImporter">
+      <HintPath>..\Ref\XNA\Microsoft.Xna.Framework.Content.Pipeline.XImporter.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Game">
+      <HintPath>..\Ref\XNA\Microsoft.Xna.Framework.Game.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Graphics">
+      <HintPath>..\Ref\XNA\Microsoft.Xna.Framework.Graphics.dll</HintPath>
+    </Reference>
+    <Reference Include="SharpDX, Version=2.4.2.0, Culture=neutral, PublicKeyToken=627a3d6d1956f55a, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>Refs\SharpDX.dll</HintPath>
+    </Reference>
+    <Reference Include="SharpDX.Direct3D9, Version=2.4.2.0, Culture=neutral, PublicKeyToken=627a3d6d1956f55a, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>Refs\SharpDX.Direct3D9.dll</HintPath>
+    </Reference>
+    <Reference Include="SharpDX.DXGI, Version=2.4.2.0, Culture=neutral, PublicKeyToken=627a3d6d1956f55a, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>Refs\SharpDX.DXGI.dll</HintPath>
+    </Reference>
+    <Reference Include="SkinnedModel, Version=1.0.0.0, Culture=neutral, processorArchitecture=x86">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>Refs\SkinnedModel.dll</HintPath>
+    </Reference>
+    <Reference Include="SkinnedModelPipeline, Version=1.0.0.0, Culture=neutral, processorArchitecture=x86">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>Refs\SkinnedModelPipeline.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Runtime.Serialization" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+    <Reference Include="Vertice.Core, Version=6.0.0.17, Culture=neutral, PublicKeyToken=4b8661552b78caf7, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>Refs\Vertice.Core.dll</HintPath>
+    </Reference>
+    <Reference Include="Vertice.Nova, Version=6.0.0.17, Culture=neutral, PublicKeyToken=4b8661552b78caf7, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>Refs\Vertice.Nova.dll</HintPath>
+    </Reference>
+    <Reference Include="Vertice.Nova.Core.DirectX10, Version=6.0.0.17, Culture=neutral, PublicKeyToken=4b8661552b78caf7, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>Refs\Vertice.Nova.Core.DirectX10.dll</HintPath>
+    </Reference>
+    <Reference Include="Vertice.Nova.Core.DirectX9, Version=6.0.0.17, Culture=neutral, PublicKeyToken=4b8661552b78caf7, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>Refs\Vertice.Nova.Core.DirectX9.dll</HintPath>
+    </Reference>
+    <Reference Include="Vertice.Nova.Interop, Version=6.0.0.17, Culture=neutral, PublicKeyToken=4b8661552b78caf7, processorArchitecture=x86">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>Refs\Vertice.Nova.Interop.dll</HintPath>
+    </Reference>
+    <Reference Include="Vertice.Wrappers.DirectX, Version=6.0.0.17, Culture=neutral, PublicKeyToken=4b8661552b78caf7, processorArchitecture=x86">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>Refs\Vertice.Wrappers.DirectX.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Entities\Export\BabylonAnimationKey.cs" />
+    <Compile Include="Entities\Export\BabylonParticleSystem.cs" />
+    <Compile Include="Entities\Export\BabylonAnimation.cs" />
+    <Compile Include="Entities\Export\BabylonShadowGenerator.cs" />
+    <Compile Include="Entities\Export\BabylonSkeleton.cs" />
+    <Compile Include="Entities\Export\BabylonBone.cs" />
+    <Compile Include="Entities\IQueryable.cs" />
+    <Compile Include="Entities\IDumpable.cs" />
+    <Compile Include="Entities\PositionNormalTexturedWeights.cs" />
+    <Compile Include="Entities\PositionNormalTextured.cs" />
+    <Compile Include="Entities\StandardMaterial.cs" />
+    <Compile Include="Entities\Export\BabylonCamera.cs" />
+    <Compile Include="Entities\Export\BabylonScene.cs" />
+    <Compile Include="Entities\Export\BabylonLight.cs" />
+    <Compile Include="Entities\Export\BabylonMesh.cs" />
+    <Compile Include="Entities\Export\BabylonMaterial.cs" />
+    <Compile Include="Entities\Export\BabylonMultiMaterial.cs" />
+    <Compile Include="Entities\Export\BabylonTexture.cs" />
+    <Compile Include="Entities\Export\BabylonSubMesh.cs" />
+    <Compile Include="Exporters\FBX\XNA\ContentBuilder.cs" />
+    <Compile Include="Exporters\FBX\XNA\ErrorLogger.cs" />
+    <Compile Include="Exporters\FBX\FBXExporter.cs" />
+    <Compile Include="Exporters\FBX\XNA\GraphicsDeviceService.cs" />
+    <Compile Include="Exporters\FBX\XNA\ServiceContainer.cs" />
+    <Compile Include="Exporters\IExporter.cs" />
+    <Compile Include="Entities\Mesh.cs" />
+    <Compile Include="Entities\ProxyMesh.cs" />
+    <Compile Include="Exporters\MXB\NovaExporter.cs" />
+    <Compile Include="Exporters\MXB\NovaExporter.Materials.cs" />
+    <Compile Include="Exporters\OBJ\Document.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Exporters\OBJ\Line.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Exporters\OBJ\MtlHeader.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Exporters\OBJ\MtlLine.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Exporters\OBJ\ObjHeader.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Exporters\OBJ\ObjExporter.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Exporters\OBJ\ObjExporter.Material.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Exporters\OBJ\ObjLine.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Program.cs" />
+    <Compile Include="Tools.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="generateAll.bat">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <None Include="Exporters\Blender\io_export_babylon.py" />
+    <None Include="Refs\xnafx40_redist.msi" />
+    <None Include="Test scenes\Chimie\BalanceDM.dds" />
+    <None Include="Test scenes\Chimie\BalanceLightingMap.dds" />
+    <None Include="Test scenes\Chimie\BoisLightingMap.dds" />
+    <None Include="Test scenes\Chimie\Book.dds" />
+    <None Include="Test scenes\Chimie\Box029CompleteMap.dds" />
+    <None Include="Test scenes\Chimie\Box079LightingMap.dds" />
+    <None Include="Test scenes\Chimie\Briquesblanches.dds" />
+    <None Include="Test scenes\Chimie\BullesB.dds" />
+    <None Include="Test scenes\Chimie\Bumpverre.dds" />
+    <None Include="Test scenes\Chimie\ChalkboardCompleteMap.dds" />
+    <None Include="Test scenes\Chimie\Chimie.dds" />
+    <None Include="Test scenes\Chimie\ChromeLightingMap.dds" />
+    <None Include="Test scenes\Chimie\Cylinder008LightingMap.dds" />
+    <None Include="Test scenes\Chimie\flamme-gaz.dds" />
+    <None Include="Test scenes\Chimie\Floor.dds" />
+    <None Include="Test scenes\Chimie\Graph.dds" />
+    <None Include="Test scenes\Chimie\Gris somreLightingMap.dds" />
+    <None Include="Test scenes\Chimie\Heart.mxb" />
+    <None Include="Test scenes\Chimie\Liquide002LightingMap.dds" />
+    <None Include="Test scenes\Chimie\Marble.dds" />
+    <None Include="Test scenes\Chimie\MursLightingMap.dds" />
+    <None Include="Test scenes\Chimie\Object1LightingMap.dds" />
+    <None Include="Test scenes\Chimie\Ordi001LightingMap.dds" />
+    <None Include="Test scenes\Chimie\OrdiDiffuseMap.dds" />
+    <None Include="Test scenes\Chimie\PaillasseLightingMap.dds" />
+    <None Include="Test scenes\Chimie\Plane003LightingMap.dds" />
+    <None Include="Test scenes\Chimie\Plaque.dds" />
+    <None Include="Test scenes\Chimie\ref1.dds" />
+    <None Include="Test scenes\Chimie\Sky.dds" />
+    <None Include="Test scenes\Chimie\VerreLightingMap.dds" />
+    <None Include="Test scenes\Chimie\Wood.dds" />
+    <None Include="Test scenes\Dude\dude.fbx" />
+    <None Include="Test scenes\Espilit\arbresmassif.dds" />
+    <None Include="Test scenes\Espilit\Blanc.dds" />
+    <None Include="Test scenes\Espilit\Booklet.dds" />
+    <None Include="Test scenes\Espilit\BouteilleBlanc.dds" />
+    <None Include="Test scenes\Espilit\BouteilleRouge.dds" />
+    <None Include="Test scenes\Espilit\ChaisesLightingMap.dds" />
+    <None Include="Test scenes\Espilit\ChaisesSpecMap.dds" />
+    <None Include="Test scenes\Espilit\Chassis table CorbuLightingMap.dds" />
+    <None Include="Test scenes\Espilit\Ciel.dds" />
+    <None Include="Test scenes\Espilit\concrete3.dds" />
+    <None Include="Test scenes\Espilit\concrete5.dds" />
+    <None Include="Test scenes\Espilit\Cuir.dds" />
+    <None Include="Test scenes\Espilit\Depliant.dds" />
+    <None Include="Test scenes\Espilit\DepliantLightingMap.dds" />
+    <None Include="Test scenes\Espilit\Espilit.mxb" />
+    <None Include="Test scenes\Espilit\Espilit.mxb.delta" />
+    <None Include="Test scenes\Espilit\Espilit.nss" />
+    <None Include="Test scenes\Espilit\Expo1.dds" />
+    <None Include="Test scenes\Espilit\Expo2.dds" />
+    <None Include="Test scenes\Espilit\Fond tableau02LightingMap.dds" />
+    <None Include="Test scenes\Espilit\Fondtableaunew02LightingMap.dds" />
+    <None Include="Test scenes\Espilit\GravierDiff.dds" />
+    <None Include="Test scenes\Espilit\herbe2.dds" />
+    <None Include="Test scenes\Espilit\Line01CompMap.dds" />
+    <None Include="Test scenes\Espilit\Line01LightingMap.dds" />
+    <None Include="Test scenes\Espilit\Metal NoirLightingMap.dds" />
+    <None Include="Test scenes\Espilit\Murs pansLightingMap.dds" />
+    <None Include="Test scenes\Espilit\MursLightingMap.dds" />
+    <None Include="Test scenes\Espilit\Noir.dds" />
+    <None Include="Test scenes\Espilit\PanneauAide.dds" />
+    <None Include="Test scenes\Espilit\Plaques Faux PlafondsLightingMap.dds" />
+    <None Include="Test scenes\Espilit\PlaquesPlafond.dds" />
+    <None Include="Test scenes\Espilit\Refcube.dds" />
+    <None Include="Test scenes\Espilit\Refcubenoire.dds" />
+    <None Include="Test scenes\Espilit\Refsol.dds" />
+    <None Include="Test scenes\Espilit\Rochers.dds" />
+    <None Include="Test scenes\Espilit\Rouge.dds" />
+    <None Include="Test scenes\Espilit\Sol.dds" />
+    <None Include="Test scenes\Espilit\SolsLightingMap.dds" />
+    <None Include="Test scenes\Espilit\Spec.dds" />
+    <None Include="Test scenes\Espilit\T33LightingMap.dds" />
+    <None Include="Test scenes\Espilit\TableauxDiffuseMap.dds" />
+    <None Include="Test scenes\Espilit\Tables bonettoLightingMap.dds" />
+    <None Include="Test scenes\Espilit\Tapis.dds" />
+    <None Include="Test scenes\Espilit\Titre1.dds" />
+    <None Include="Test scenes\Espilit\TitreAide.dds" />
+    <None Include="Test scenes\Espilit\TitreCam.dds" />
+    <None Include="Test scenes\Espilit\Toile.dds" />
+    <None Include="Test scenes\Espilit\Tree.dds" />
+    <None Include="Test scenes\Espilit\VerreBump.dds" />
+    <None Include="Test scenes\Flat2009\1.dds" />
+    <None Include="Test scenes\Flat2009\2.dds" />
+    <None Include="Test scenes\Flat2009\3.dds" />
+    <None Include="Test scenes\Flat2009\3602.dds" />
+    <None Include="Test scenes\Flat2009\3602low.dds" />
+    <None Include="Test scenes\Flat2009\4.dds" />
+    <None Include="Test scenes\Flat2009\Affiches.dds" />
+    <None Include="Test scenes\Flat2009\Affiches2.dds" />
+    <None Include="Test scenes\Flat2009\AquariumLM.dds" />
+    <None Include="Test scenes\Flat2009\BathTapis.dds" />
+    <None Include="Test scenes\Flat2009\beton.dds" />
+    <None Include="Test scenes\Flat2009\Betonmurs.dds" />
+    <None Include="Test scenes\Flat2009\Bibelots.dds" />
+    <None Include="Test scenes\Flat2009\bibelotslightingmap.dds" />
+    <None Include="Test scenes\Flat2009\boisclair.dds" />
+    <None Include="Test scenes\Flat2009\Boisplandetravail.dds" />
+    <None Include="Test scenes\Flat2009\Boisrouge.dds" />
+    <None Include="Test scenes\Flat2009\bOUQUINS.DDS" />
+    <None Include="Test scenes\Flat2009\Bruitverre.dds" />
+    <None Include="Test scenes\Flat2009\Btn.dds" />
+    <None Include="Test scenes\Flat2009\Btn2.dds" />
+    <None Include="Test scenes\Flat2009\Btn3.dds" />
+    <None Include="Test scenes\Flat2009\Bulles.dds" />
+    <None Include="Test scenes\Flat2009\Bumpcuir.dds" />
+    <None Include="Test scenes\Flat2009\canap1lightingmap.dds" />
+    <None Include="Test scenes\Flat2009\canap1lightingmap2.dds" />
+    <None Include="Test scenes\Flat2009\CarreauxVerreBump.dds" />
+    <None Include="Test scenes\Flat2009\CarreauxVerreDiff.dds" />
+    <None Include="Test scenes\Flat2009\CarreauxVerreNM.dds" />
+    <None Include="Test scenes\Flat2009\ChassisboisLightingMap.dds" />
+    <None Include="Test scenes\Flat2009\Clavier2.dds" />
+    <None Include="Test scenes\Flat2009\CouverturesA.dds" />
+    <None Include="Test scenes\Flat2009\Couvrante1.dds" />
+    <None Include="Test scenes\Flat2009\Couvrante2.dds" />
+    <None Include="Test scenes\Flat2009\cuir.dds" />
+    <None Include="Test scenes\Flat2009\cuirBleu.dds" />
+    <None Include="Test scenes\Flat2009\cuirNoir.dds" />
+    <None Include="Test scenes\Flat2009\Cuivre.dds" />
+    <None Include="Test scenes\Flat2009\drapsNM.dds" />
+    <None Include="Test scenes\Flat2009\Eau.dds" />
+    <None Include="Test scenes\Flat2009\EcranPC1.dds" />
+    <None Include="Test scenes\Flat2009\Facade.dds" />
+    <None Include="Test scenes\Flat2009\Faience.dds" />
+    <None Include="Test scenes\Flat2009\Flat2009.mxb" />
+    <None Include="Test scenes\Flat2009\four.dds" />
+    <None Include="Test scenes\Flat2009\Fresnel1.dds" />
+    <None Include="Test scenes\Flat2009\Fresnel2.dds" />
+    <None Include="Test scenes\Flat2009\GresNM.dds" />
+    <None Include="Test scenes\Flat2009\Grille.dds" />
+    <None Include="Test scenes\Flat2009\Grès.dds" />
+    <None Include="Test scenes\Flat2009\GuitareExplo.dds" />
+    <None Include="Test scenes\Flat2009\GuitareFV.dds" />
+    <None Include="Test scenes\Flat2009\GuitarSG.dds" />
+    <None Include="Test scenes\Flat2009\Halo.dds" />
+    <None Include="Test scenes\Flat2009\Halogene.dds" />
+    <None Include="Test scenes\Flat2009\Here.dds" />
+    <None Include="Test scenes\Flat2009\induction.dds" />
+    <None Include="Test scenes\Flat2009\Inter.dds" />
+    <None Include="Test scenes\Flat2009\LakeRef.dds" />
+    <None Include="Test scenes\Flat2009\LampeSalonDiff.dds" />
+    <None Include="Test scenes\Flat2009\Layout.dds" />
+    <None Include="Test scenes\Flat2009\Machines.dds" />
+    <None Include="Test scenes\Flat2009\Marbre1.dds" />
+    <None Include="Test scenes\Flat2009\MarkLitCHParents.dds" />
+    <None Include="Test scenes\Flat2009\MarkMarshall.dds" />
+    <None Include="Test scenes\Flat2009\MarkMobilier.dds" />
+    <None Include="Test scenes\Flat2009\MarkRideauCatz.dds" />
+    <None Include="Test scenes\Flat2009\MarkSolCHparents.dds" />
+    <None Include="Test scenes\Flat2009\Marshall.dds" />
+    <None Include="Test scenes\Flat2009\MCanape.dds" />
+    <None Include="Test scenes\Flat2009\Mcanape3.dds" />
+    <None Include="Test scenes\Flat2009\Metal1.dds" />
+    <None Include="Test scenes\Flat2009\meubleslightingmap.dds" />
+    <None Include="Test scenes\Flat2009\MExplor.dds" />
+    <None Include="Test scenes\Flat2009\Mfauteuil.dds" />
+    <None Include="Test scenes\Flat2009\MFLying.dds" />
+    <None Include="Test scenes\Flat2009\Mfour.dds" />
+    <None Include="Test scenes\Flat2009\MoquetteRouge.dds" />
+    <None Include="Test scenes\Flat2009\MoquetteSAM.dds" />
+    <None Include="Test scenes\Flat2009\MoquetteVerte.dds" />
+    <None Include="Test scenes\Flat2009\MoquetteVioline.dds" />
+    <None Include="Test scenes\Flat2009\MSG.dds" />
+    <None Include="Test scenes\Flat2009\MTableauSalon.dds" />
+    <None Include="Test scenes\Flat2009\Mtele.dds" />
+    <None Include="Test scenes\Flat2009\MurCh1.dds" />
+    <None Include="Test scenes\Flat2009\MurCH2.dds" />
+    <None Include="Test scenes\Flat2009\MurCh3.dds" />
+    <None Include="Test scenes\Flat2009\MurEditBrique.dds" />
+    <None Include="Test scenes\Flat2009\MurEditBriqueNM.dds" />
+    <None Include="Test scenes\Flat2009\MurEditStickers.dds" />
+    <None Include="Test scenes\Flat2009\MurEditStickers2.dds" />
+    <None Include="Test scenes\Flat2009\MurEditStickersSpec.dds" />
+    <None Include="Test scenes\Flat2009\murschambreverteNM.dds" />
+    <None Include="Test scenes\Flat2009\Murscuisine.dds" />
+    <None Include="Test scenes\Flat2009\MurSDB.dds" />
+    <None Include="Test scenes\Flat2009\MurSDBBump.dds" />
+    <None Include="Test scenes\Flat2009\MursToilettes.dds" />
+    <None Include="Test scenes\Flat2009\MursToilettes2.dds" />
+    <None Include="Test scenes\Flat2009\MursToilettes2Spec.dds" />
+    <None Include="Test scenes\Flat2009\paillasse.dds" />
+    <None Include="Test scenes\Flat2009\paintsalon.dds" />
+    <None Include="Test scenes\Flat2009\PaintSalon2.dds" />
+    <None Include="Test scenes\Flat2009\PaintSalon3.dds" />
+    <None Include="Test scenes\Flat2009\Part1.dds" />
+    <None Include="Test scenes\Flat2009\PlanteA2Alt.dds" />
+    <None Include="Test scenes\Flat2009\PlanteAAlt.dds" />
+    <None Include="Test scenes\Flat2009\PlanteaLT.dds" />
+    <None Include="Test scenes\Flat2009\poigneefenetreslightingmap.dds" />
+    <None Include="Test scenes\Flat2009\Poisson1Alt.dds" />
+    <None Include="Test scenes\Flat2009\PPbois.dds" />
+    <None Include="Test scenes\Flat2009\PPboisNM.DDS" />
+    <None Include="Test scenes\Flat2009\PriseMurale.dds" />
+    <None Include="Test scenes\Flat2009\Ref1.dds" />
+    <None Include="Test scenes\Flat2009\RefChrome.dds" />
+    <None Include="Test scenes\Flat2009\RefChromeRouge.dds" />
+    <None Include="Test scenes\Flat2009\RefTableau.dds" />
+    <None Include="Test scenes\Flat2009\Ref_probe.dds" />
+    <None Include="Test scenes\Flat2009\SAMParquet.dds" />
+    <None Include="Test scenes\Flat2009\SANDAlt.dds" />
+    <None Include="Test scenes\Flat2009\Serviettes.dds" />
+    <None Include="Test scenes\Flat2009\Shanghai_1933.dds" />
+    <None Include="Test scenes\Flat2009\Solcarreaux.dds" />
+    <None Include="Test scenes\Flat2009\Solcarreauxbump.dds" />
+    <None Include="Test scenes\Flat2009\sollightingmap.dds" />
+    <None Include="Test scenes\Flat2009\Souris.dds" />
+    <None Include="Test scenes\Flat2009\tablauxlightingmap.dds" />
+    <None Include="Test scenes\Flat2009\TapisserieJaune.dds" />
+    <None Include="Test scenes\Flat2009\Tele.dds" />
+    <None Include="Test scenes\Flat2009\Telespec.dds" />
+    <None Include="Test scenes\Flat2009\tentures.dds" />
+    <None Include="Test scenes\Flat2009\tentures2.dds" />
+    <None Include="Test scenes\Flat2009\Test2.dds" />
+    <None Include="Test scenes\Flat2009\vitres01lightingmap.dds" />
+    <None Include="Test scenes\Flat2009\wallslightingmap2.dds" />
+    <None Include="Test scenes\Flat2009\wallslightingmap3.dds" />
+    <None Include="Test scenes\Rabbit\Rabbit.fbx" />
+    <None Include="Test scenes\Robot\Robot.mxb" />
+    <None Include="Test scenes\SpaceDeK\Bidule1.dds" />
+    <None Include="Test scenes\SpaceDeK\Bidule1SI.dds" />
+    <None Include="Test scenes\SpaceDeK\Bidulelaser.dds" />
+    <None Include="Test scenes\SpaceDeK\BidulelaserSI.dds" />
+    <None Include="Test scenes\SpaceDeK\BiduleOmega.dds" />
+    <None Include="Test scenes\SpaceDeK\Biduleshield.dds" />
+    <None Include="Test scenes\SpaceDeK\BiduleShieldSI.dds" />
+    <None Include="Test scenes\SpaceDeK\Boss1DiffuseMap.dds" />
+    <None Include="Test scenes\SpaceDeK\Boss1Spec.dds" />
+    <None Include="Test scenes\SpaceDeK\Ennemi1DiffuseMap.dds" />
+    <None Include="Test scenes\SpaceDeK\Ennemi1SpecularMap.dds" />
+    <None Include="Test scenes\SpaceDeK\Explo.dds" />
+    <None Include="Test scenes\SpaceDeK\Explo2.dds" />
+    <None Include="Test scenes\SpaceDeK\Laser1.dds" />
+    <None Include="Test scenes\SpaceDeK\Laser2.dds" />
+    <None Include="Test scenes\SpaceDeK\Missile.DDS" />
+    <None Include="Test scenes\SpaceDeK\Part.dds" />
+    <None Include="Test scenes\SpaceDeK\Premplan.dds" />
+    <None Include="Test scenes\SpaceDeK\Protec.dds" />
+    <None Include="Test scenes\SpaceDeK\ProtecSpec.dds" />
+    <None Include="Test scenes\SpaceDeK\refext2.dds" />
+    <None Include="Test scenes\SpaceDeK\SpaceDek.mxb" />
+    <None Include="Test scenes\Spaceship\SpaceShip.fbx" />
+    <None Include="Test scenes\TestAnim\testanim.mxb" />
+    <None Include="Test scenes\TheCar\BarresLightingMap.dds" />
+    <None Include="Test scenes\TheCar\beigeLightingMap.dds" />
+    <None Include="Test scenes\TheCar\Bequet.dds" />
+    <None Include="Test scenes\TheCar\BequetB.dds" />
+    <None Include="Test scenes\TheCar\Bequetnoir.dds" />
+    <None Include="Test scenes\TheCar\betonext.dds" />
+    <None Include="Test scenes\TheCar\bodyLightingMap.dds" />
+    <None Include="Test scenes\TheCar\Bois.dds" />
+    <None Include="Test scenes\TheCar\Boutons.dds" />
+    <None Include="Test scenes\TheCar\BOUTONS2.dds" />
+    <None Include="Test scenes\TheCar\C-Max_commande_retrosDiffuseMap.dds" />
+    <None Include="Test scenes\TheCar\CarrosserieLightingMap.dds" />
+    <None Include="Test scenes\TheCar\CarrosserieLightingMapB.dds" />
+    <None Include="Test scenes\TheCar\CarrosserieLightingMapNoire.dds" />
+    <None Include="Test scenes\TheCar\ChassisverreLightingMap.dds" />
+    <None Include="Test scenes\TheCar\cheminee.dds" />
+    <None Include="Test scenes\TheCar\ChemineeLightingMap.dds" />
+    <None Include="Test scenes\TheCar\Ciel15.dds" />
+    <None Include="Test scenes\TheCar\Ciment1.dds" />
+    <None Include="Test scenes\TheCar\Ciment1NM.dds" />
+    <None Include="Test scenes\TheCar\Cligno.dds" />
+    <None Include="Test scenes\TheCar\degradecine.dds" />
+    <None Include="Test scenes\TheCar\DSC_5082.dds" />
+    <None Include="Test scenes\TheCar\eaubump.dds" />
+    <None Include="Test scenes\TheCar\Feuarr.dds" />
+    <None Include="Test scenes\TheCar\FeuxarrNM.dds" />
+    <None Include="Test scenes\TheCar\flare0.dds" />
+    <None Include="Test scenes\TheCar\Ford_02.dds" />
+    <None Include="Test scenes\TheCar\foret.dds" />
+    <None Include="Test scenes\TheCar\Ghia.dds" />
+    <None Include="Test scenes\TheCar\goudron.dds" />
+    <None Include="Test scenes\TheCar\gps.dds" />
+    <None Include="Test scenes\TheCar\gRILLE.dds" />
+    <None Include="Test scenes\TheCar\gRILLEnm.dds" />
+    <None Include="Test scenes\TheCar\immeublesLightingMap.dds" />
+    <None Include="Test scenes\TheCar\interface.dds" />
+    <None Include="Test scenes\TheCar\layout.dds" />
+    <None Include="Test scenes\TheCar\LAYOUT3.dds" />
+    <None Include="Test scenes\TheCar\leather_bump.dds" />
+    <None Include="Test scenes\TheCar\Line03LightingMap.dds" />
+    <None Include="Test scenes\TheCar\lumLightingMap.dds" />
+    <None Include="Test scenes\TheCar\Madewith58.dds" />
+    <None Include="Test scenes\TheCar\Metal.dds" />
+    <None Include="Test scenes\TheCar\MetalLightingMap.dds" />
+    <None Include="Test scenes\TheCar\metalrouille.dds" />
+    <None Include="Test scenes\TheCar\metalrouilleNM.dds" />
+    <None Include="Test scenes\TheCar\metalrouilletubes.dds" />
+    <None Include="Test scenes\TheCar\metalrouilletubesNM.dds" />
+    <None Include="Test scenes\TheCar\Murs1.dds" />
+    <None Include="Test scenes\TheCar\Murs1NM.dds" />
+    <None Include="Test scenes\TheCar\Mursext.dds" />
+    <None Include="Test scenes\TheCar\MursLightingMap.dds" />
+    <None Include="Test scenes\TheCar\Phareav.dds" />
+    <None Include="Test scenes\TheCar\Plaque.dds" />
+    <None Include="Test scenes\TheCar\PlaqueLightingMap.dds" />
+    <None Include="Test scenes\TheCar\PlaqueNM.dds" />
+    <None Include="Test scenes\TheCar\Plaqueshautes.dds" />
+    <None Include="Test scenes\TheCar\PlaqueshautesNM.dds" />
+    <None Include="Test scenes\TheCar\portable.dds" />
+    <None Include="Test scenes\TheCar\Porte1LightingMap.dds" />
+    <None Include="Test scenes\TheCar\PortesMetal.dds" />
+    <None Include="Test scenes\TheCar\PortesMetalNM.dds" />
+    <None Include="Test scenes\TheCar\PoteauIPNLightingMap.dds" />
+    <None Include="Test scenes\TheCar\PoutreLightingMap.dds" />
+    <None Include="Test scenes\TheCar\refcube3.dds" />
+    <None Include="Test scenes\TheCar\refcubephare.dds" />
+    <None Include="Test scenes\TheCar\Refsalon2.dds" />
+    <None Include="Test scenes\TheCar\reftest.dds" />
+    <None Include="Test scenes\TheCar\SolEcxtLightingMap.dds" />
+    <None Include="Test scenes\TheCar\SoustoitLightingMap.dds" />
+    <None Include="Test scenes\TheCar\Spec.dds" />
+    <None Include="Test scenes\TheCar\SupportstubesLightingMap.dds" />
+    <None Include="Test scenes\TheCar\TheCar.mxb" />
+    <None Include="Test scenes\TheCar\TubesLightingMap.dds" />
+    <None Include="Test scenes\TheCar\tyre002b.dds" />
+    <None Include="Test scenes\TheCar\vitesses.dds" />
+    <None Include="Test scenes\TheCar\Vitres opac.dds" />
+    <None Include="Test scenes\TheCar\Vitres.dds" />
+    <None Include="Test scenes\TheCar\vitrescasees1.dds" />
+    <None Include="Test scenes\TheCar\vitrescasees2.dds" />
+    <None Include="Test scenes\TheCar\vitresloin.dds" />
+    <None Include="Test scenes\TheCar\volant.dds" />
+    <None Include="Test scenes\TheCar\wood.dds" />
+    <None Include="Test scenes\TheCar\WOODlm.dds" />
+    <None Include="Test scenes\Viper\Viper.mtl" />
+    <None Include="Test scenes\Viper\Viper.obj" />
+    <None Include="App.config" />
+    <None Include="Exporters\FBX\XNA\XNA Game Studio\Microsoft.Xna.GameStudio.ContentPipelineExtensions.targets">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="Exporters\FBX\XNA\XNA Game Studio\Microsoft.Xna.GameStudio.targets">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="Exporters\FBX\XNA\XNA Game Studio\v4.0\Microsoft.Xna.GameStudio.AvailablePlatforms.targets">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="Exporters\FBX\XNA\XNA Game Studio\v4.0\Microsoft.Xna.GameStudio.Common.targets">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="Exporters\FBX\XNA\XNA Game Studio\v4.0\Microsoft.Xna.GameStudio.Content.targets">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="Exporters\FBX\XNA\XNA Game Studio\v4.0\Microsoft.Xna.GameStudio.ContentPipeline.targets">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="Exporters\FBX\XNA\XNA Game Studio\v4.0\Microsoft.Xna.GameStudio.Windows.targets">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="Exporters\FBX\XNA\XNA Game Studio\v4.0\Microsoft.Xna.GameStudio.Xbox 360.targets">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="packages.config" />
+    <None Include="Test scenes\Wcafe\Affiches.dds" />
+    <None Include="Test scenes\Wcafe\Affiches2.dds" />
+    <None Include="Test scenes\Wcafe\Affiches3.dds" />
+    <None Include="Test scenes\Wcafe\AffichesLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Bafle.dds" />
+    <None Include="Test scenes\Wcafe\BafleLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Beton1.dds" />
+    <None Include="Test scenes\Wcafe\BlancUniLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Bois2.dds" />
+    <None Include="Test scenes\Wcafe\Briques3.dds" />
+    <None Include="Test scenes\Wcafe\Canapé1LightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Canette1.dds" />
+    <None Include="Test scenes\Wcafe\Canette2.dds" />
+    <None Include="Test scenes\Wcafe\ChaineHifi.dds" />
+    <None Include="Test scenes\Wcafe\ChaineHifi2.dds" />
+    <None Include="Test scenes\Wcafe\ChromeBrosséLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\ChromeLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\ColonnesLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Coussins2LightingMap.dds" />
+    <None Include="Test scenes\Wcafe\CoussinsfauteuilLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Cuir1Spec.dds" />
+    <None Include="Test scenes\Wcafe\Cuirbrun.dds" />
+    <None Include="Test scenes\Wcafe\CuirbrunSpec.dds" />
+    <None Include="Test scenes\Wcafe\CuiViolet.dds" />
+    <None Include="Test scenes\Wcafe\Degradebar.dds" />
+    <None Include="Test scenes\Wcafe\Degradé.dds" />
+    <None Include="Test scenes\Wcafe\Ecrantele1.dds" />
+    <None Include="Test scenes\Wcafe\EscalierLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\exit.dds" />
+    <None Include="Test scenes\Wcafe\FauteuilRond01LightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Fauteuilsronds.dds" />
+    <None Include="Test scenes\Wcafe\Fndgris.dds" />
+    <None Include="Test scenes\Wcafe\Fndrouge2.dds" />
+    <None Include="Test scenes\Wcafe\Fondmeuble basLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Fvert.dds" />
+    <None Include="Test scenes\Wcafe\Grille.dds" />
+    <None Include="Test scenes\Wcafe\liquiorange.dds" />
+    <None Include="Test scenes\Wcafe\Liquirouge.dds" />
+    <None Include="Test scenes\Wcafe\Liquivert.dds" />
+    <None Include="Test scenes\Wcafe\Logo.dds" />
+    <None Include="Test scenes\Wcafe\Masque1.dds" />
+    <None Include="Test scenes\Wcafe\Masque2.dds" />
+    <None Include="Test scenes\Wcafe\MurrdcLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Mursdivers.dds" />
+    <None Include="Test scenes\Wcafe\NeonarcheAmbiant.dds" />
+    <None Include="Test scenes\Wcafe\NoirmatLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Ordi.dds" />
+    <None Include="Test scenes\Wcafe\OrdiSI.dds" />
+    <None Include="Test scenes\Wcafe\OrdisLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Pano2Alt.dds" />
+    <None Include="Test scenes\Wcafe\Pano5refNoirpurFloue.dds" />
+    <None Include="Test scenes\Wcafe\Parquet1.dds" />
+    <None Include="Test scenes\Wcafe\Parquet3.dds" />
+    <None Include="Test scenes\Wcafe\Peintureverte.dds" />
+    <None Include="Test scenes\Wcafe\PlafondsLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Plancher2LightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Plancherétage1LightingMap.dds" />
+    <None Include="Test scenes\Wcafe\PlotDiffuseMap.dds" />
+    <None Include="Test scenes\Wcafe\Produits.dds" />
+    <None Include="Test scenes\Wcafe\RedFlowers.dds" />
+    <None Include="Test scenes\Wcafe\Refcubenoire.dds" />
+    <None Include="Test scenes\Wcafe\Refcubenoireplate.dds" />
+    <None Include="Test scenes\Wcafe\Salade.dds" />
+    <None Include="Test scenes\Wcafe\SaladesLM.dds" />
+    <None Include="Test scenes\Wcafe\SolRDCLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\SpecMetalbrossé.dds" />
+    <None Include="Test scenes\Wcafe\Sponsor01DiffuseMap.dds" />
+    <None Include="Test scenes\Wcafe\Sticker haut.dds" />
+    <None Include="Test scenes\Wcafe\Surface.dds" />
+    <None Include="Test scenes\Wcafe\tableaux.dds" />
+    <None Include="Test scenes\Wcafe\TableSurfaceLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\tapis4.dds" />
+    <None Include="Test scenes\Wcafe\TapisLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Tele.dds" />
+    <None Include="Test scenes\Wcafe\TeleSI.dds" />
+    <None Include="Test scenes\Wcafe\TéléLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\vENT.dds" />
+    <None Include="Test scenes\Wcafe\Verticola.dds" />
+    <None Include="Test scenes\Wcafe\Wcafe.mxb" />
+    <None Include="Test scenes\Wcafe\Wifi.dds" />
+    <None Include="Test scenes\Wcafe\Win7.dds" />
+    <None Include="Test scenes\Wcafe\Win7A.dds" />
+    <None Include="Test scenes\Wcafe\WinCafé1.dds" />
+    <None Include="Test scenes\Wcafe\WinCafé1IL.dds" />
+    <None Include="Test scenes\Wcafe\xBOXLightingMap.dds" />
+    <None Include="Test scenes\Wcafe\Xbrique.dds" />
+    <None Include="Test scenes\Wcafe\Zebu.dds" />
+    <None Include="Test scenes\Wcafe\ZincLightingMap.dds" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Exporters\FBX\XNA\XNA Game Studio\v4.0\Microsoft.Xna.Framework.Tools.Packaging.Tasks.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="DirectShow.Net.dll">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Content>
+    <Content Include="Refs\Microsoft.Xna.Framework.Content.Pipeline.AudioImporters.dll" />
+    <Content Include="Refs\Microsoft.Xna.Framework.Content.Pipeline.dll" />
+    <Content Include="Refs\Microsoft.Xna.Framework.Content.Pipeline.EffectImporter.dll" />
+    <Content Include="Refs\Microsoft.Xna.Framework.Content.Pipeline.FBXImporter.dll" />
+    <Content Include="Refs\Microsoft.Xna.Framework.Content.Pipeline.TextureImporter.dll" />
+    <Content Include="Refs\Microsoft.Xna.Framework.Content.Pipeline.VideoImporters.dll" />
+    <Content Include="Refs\Microsoft.Xna.Framework.Content.Pipeline.XImporter.dll" />
+    <Content Include="Refs\Microsoft.Xna.Framework.Tools.Packaging.Tasks.dll" />
+    <Content Include="Refs\SharpDX.Direct3D9.dll" />
+    <Content Include="Refs\SharpDX.DXGI.dll" />
+    <Content Include="Refs\SkinnedModel.dll" />
+    <Content Include="Refs\SkinnedModelPipeline.dll" />
+    <Content Include="Refs\Vertice.Nova.Core.DirectX10.dll" />
+    <Content Include="Test scenes\Chimie\Coeur.jpg" />
+    <Content Include="Test scenes\Chimie\heartSpecjpg.jpg" />
+    <Content Include="Test scenes\Chimie\Labels.png" />
+    <Content Include="Test scenes\Dude\head.tga" />
+    <Content Include="Test scenes\Dude\jacket.tga" />
+    <Content Include="Test scenes\Dude\pants.tga" />
+    <Content Include="Test scenes\Dude\upBodyC.tga" />
+    <Content Include="Test scenes\Espilit\NovaScreenshot.jpg" />
+    <Content Include="Test scenes\Robot\DispenderDiffuseMap.dds" />
+    <Content Include="Test scenes\Robot\Dégrade.png" />
+    <Content Include="Test scenes\Robot\EnvAmbient Occlusion _MR.dds" />
+    <Content Include="Test scenes\Robot\Ref.dds" />
+    <Content Include="Test scenes\Robot\RobotCompmap.dds" />
+    <Content Include="Test scenes\Robot\RobotSpec.dds" />
+    <Content Include="Test scenes\Robot\Slide1.dds" />
+    <Content Include="Test scenes\SpaceDeK\FondSpace.jpg" />
+    <Content Include="Test scenes\SpaceDeK\Missile1SE.png" />
+    <Content Include="Test scenes\SpaceDeK\Missilespec.png" />
+    <Content Include="Test scenes\SpaceDeK\Part.jpg" />
+    <Content Include="Test scenes\SpaceDeK\react.jpg" />
+    <Content Include="Test scenes\SpaceDeK\React2.jpg" />
+    <Content Include="Test scenes\SpaceDeK\Vaisseau.bmp" />
+    <Content Include="Test scenes\SpaceDeK\Vaisseau000.bmp" />
+    <Content Include="Test scenes\SpaceDeK\VaisseauDiffuseMap.jpg" />
+    <Content Include="Test scenes\SpaceDeK\VaisseauSpecularMap.jpg" />
+    <Content Include="Test scenes\Spaceship\wedge_p2_diff_v1.tga" />
+    <Content Include="Test scenes\Viper\aripa-buna.jpg" />
+    <Content Include="Test scenes\Viper\carlinga-specular.jpg" />
+    <Content Include="Test scenes\Viper\carlinga.jpg" />
+    <Content Include="Test scenes\Viper\carma-creasta.jpg" />
+    <Content Include="Test scenes\Viper\carmaaripi.jpg" />
+    <Content Include="Test scenes\Viper\elicie.jpg" />
+    <Content Include="Test scenes\Viper\engine-cover-bump.jpg" />
+    <Content Include="Test scenes\Viper\engine-cover.jpg" />
+    <Content Include="Test scenes\Viper\engine-covers-specular.jpg" />
+    <Content Include="Test scenes\Viper\face-bump.jpg" />
+    <Content Include="Test scenes\Viper\face-specular.jpg" />
+    <Content Include="Test scenes\Viper\face.jpg" />
+    <Content Include="Test scenes\Viper\gun-romb.jpg" />
+    <Content Include="Test scenes\Viper\parbriz.jpg" />
+    <Content Include="Test scenes\Viper\Untitled-1.jpg" />
+    <Content Include="Test scenes\Viper\wing-bump.jpg" />
+    <Content Include="Test scenes\Viper\wing-specular.jpg" />
+    <Content Include="Test scenes\Viper\wing-up-bump.jpg" />
+    <Content Include="Test scenes\Viper\wing-up-specular.jpg" />
+    <Content Include="Test scenes\Viper\wing-up.jpg" />
+    <Content Include="Refs\SharpDX.dll" />
+    <Content Include="Refs\Vertice.Core.dll" />
+    <Content Include="Refs\Vertice.Nova.Core.DirectX9.dll" />
+    <Content Include="Refs\Vertice.Nova.dll" />
+    <Content Include="Refs\Vertice.Nova.Interop.dll" />
+    <Content Include="Refs\Vertice.Wrappers.DirectX.dll" />
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Properties\" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include=".NETFramework,Version=v4.0">
+      <Visible>False</Visible>
+      <ProductName>Microsoft .NET Framework 4 %28x86 and x64%29</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.4.5">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 4.5</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

BIN
Exporters/FBX - OBJ/BabylonExport/DirectShow.Net.dll


+ 35 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonAnimation.cs

@@ -0,0 +1,35 @@
+using System.Runtime.Serialization;
+using Vertice.Nova.Animations;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonAnimation
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public string property { get; set; }
+
+        [DataMember]
+        public DataType dataType { get; set; }
+
+        [DataMember]
+        public InterpolationLoop loopBehavior { get; set; }
+
+        [DataMember]
+        public int framePerSecond { get; set; }
+
+        [DataMember]
+        public BabylonAnimationKey[] keys { get; set; }
+
+        public enum DataType
+        {
+            Float = 0,
+            Vector3 = 1,
+            Quaternion = 2,
+            Matrix = 3
+        }
+    }
+}

+ 14 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonAnimationKey.cs

@@ -0,0 +1,14 @@
+using System.Runtime.Serialization;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonAnimationKey
+    {
+        [DataMember]
+        public float frame { get; set; }
+
+        [DataMember]
+        public float[] values { get; set; }
+    }
+}

+ 24 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonBone.cs

@@ -0,0 +1,24 @@
+using System.Runtime.Serialization;
+using Vertice.Nova.Animations;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonBone
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public int index { get; set; }
+
+        [DataMember]
+        public int parentBoneIndex { get; set; }
+
+        [DataMember]
+        public float[] matrix { get; set; }
+
+        [DataMember]
+        public BabylonAnimation animation { get; set; }
+    }
+}

+ 61 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonCamera.cs

@@ -0,0 +1,61 @@
+using System.Runtime.Serialization;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonCamera
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public string id { get; set; }
+
+        [DataMember]
+        public float[] position { get; set; }
+
+        [DataMember]
+        public float[] rotation { get; set; }
+
+        [DataMember]
+        public float[] target { get; set; }
+
+        [DataMember]
+        public float fov { get; set; }
+
+        [DataMember]
+        public float minZ { get; set; }
+
+        [DataMember]
+        public float maxZ { get; set; }
+
+        [DataMember]
+        public float speed { get; set; }
+
+        [DataMember]
+        public float inertia { get; set; }
+
+        [DataMember]
+        public bool checkCollisions { get; set; }
+
+        [DataMember]
+        public bool applyGravity { get; set; }
+
+        [DataMember]
+        public float[] ellipsoid { get; set; }
+
+
+        public BabylonCamera()
+        {
+            position = new[] { 0f, 0f, 0f };
+            rotation = new[] { 0f, 0f, 0f };
+
+            // Default values
+            fov = 0.8f;
+            minZ = 0.1f;
+            maxZ = 5000.0f;
+            speed = 1.0f;
+            inertia = 0.9f;
+        }
+    }
+}

+ 39 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonLight.cs

@@ -0,0 +1,39 @@
+using System.Runtime.Serialization;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonLight
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public string id { get; set; }
+
+        [DataMember]
+        public float[] position { get; set; }
+
+        [DataMember]
+        public float[] direction { get; set; }
+
+        [DataMember]
+        public int type { get; set; }
+
+        [DataMember]
+        public float[] diffuse { get; set; }
+
+        [DataMember]
+        public float[] specular { get; set; }
+
+        [DataMember]
+        public float intensity { get; set; }
+
+        public BabylonLight()
+        {
+            diffuse = new[] {1.0f, 1.0f, 1.0f};
+            specular = new[] { 1.0f, 1.0f, 1.0f };
+            intensity = 1.0f;
+        }
+    }
+}

+ 68 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonMaterial.cs

@@ -0,0 +1,68 @@
+using System.Runtime.Serialization;
+using BabylonExport.Exporters;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonMaterial
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public string id { get; set; }
+
+        [DataMember]
+        public bool backFaceCulling { get; set; }
+
+        [DataMember]
+        public float[] ambient { get; set; }
+
+        [DataMember]
+        public float[] diffuse { get; set; }
+
+        [DataMember]
+        public float[] specular { get; set; }
+
+        [DataMember]
+        public float[] emissive { get; set; }
+
+        [DataMember]
+        public float specularPower { get; set; }
+
+        [DataMember]
+        public float alpha { get; set; }
+
+        [DataMember]
+        public BabylonTexture diffuseTexture { get; set; }
+
+        [DataMember]
+        public BabylonTexture ambientTexture { get; set; }
+
+        [DataMember]
+        public BabylonTexture opacityTexture { get; set; }
+
+        [DataMember]
+        public BabylonTexture reflectionTexture { get; set; }
+
+        [DataMember]
+        public BabylonTexture emissiveTexture { get; set; }
+
+        [DataMember]
+        public BabylonTexture specularTexture { get; set; }
+
+        [DataMember]
+        public BabylonTexture bumpTexture { get; set; }
+
+        public BabylonMaterial()
+        {
+            backFaceCulling = true;
+            ambient = new[] {1.0f, 1.0f, 1.0f};
+            diffuse = new[] { 1.0f, 1.0f, 1.0f };
+            specular = new[] { 1.0f, 1.0f, 1.0f };
+            emissive = new[] { 0f, 0f, 0f };
+            specularPower = 64;
+            alpha = 1.0f;
+        }
+    }
+}

+ 111 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonMesh.cs

@@ -0,0 +1,111 @@
+using System.Runtime.Serialization;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonMesh
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public string id { get; set; }
+
+        [DataMember]
+        public string parentId { get; set; }
+
+        [DataMember]
+        public string materialId { get; set; }
+
+        [DataMember]
+        public bool isEnabled { get; set; }
+
+        [DataMember]
+        public bool isVisible { get; set; }
+
+        [DataMember]
+        public float[] position { get; set; }
+
+        [DataMember]
+        public float[] rotation { get; set; }
+
+        [DataMember]
+        public float[] scaling { get; set; }
+
+        [DataMember]
+        public float[] localMatrix { get; set; }
+
+        [DataMember]
+        public float[] positions { get; set; }
+
+        [DataMember]
+        public float[] normals { get; set; }
+
+        [DataMember]
+        public float[] uvs { get; set; }
+
+        [DataMember]
+        public float[] uvs2 { get; set; }
+
+        [DataMember]
+        public float[] colors { get; set; }
+
+        [DataMember]
+        public int[] matricesIndices { get; set; }
+
+        [DataMember]
+        public float[] matricesWeights { get; set; }
+
+        [DataMember]
+        public int[] indices { get; set; }
+
+        [DataMember]
+        public bool checkCollisions { get; set; }
+
+        [DataMember]
+        public bool receiveShadows { get; set; }        
+
+        [DataMember]
+        public int billboardMode { get; set; }
+
+        [DataMember]
+        public float visibility { get; set; }
+
+        [DataMember]
+        public BabylonSubMesh[] subMeshes { get; set; }
+
+        [DataMember]
+        public int skeletonId { get; set; }
+
+        [DataMember]
+        public bool autoAnimate { get; set; }
+
+        [DataMember]
+        public int autoAnimateFrom { get; set; }
+
+        [DataMember]
+        public int autoAnimateTo { get; set; }
+
+        [DataMember]
+        public bool autoAnimateLoop { get; set; }
+
+        [DataMember]
+        public BabylonAnimation[] animations { get; set; }
+
+        public BabylonMesh()
+        {
+            isEnabled = true;
+            isVisible = true;
+
+            position = new[] { 0f, 0f, 0f };
+            rotation = new[] { 0f, 0f, 0f };
+            scaling = new[] { 1f, 1f, 1f };
+
+            billboardMode = 0;
+
+            visibility = 1.0f;
+
+            skeletonId = -1;
+        }
+    }
+}

+ 17 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonMultiMaterial.cs

@@ -0,0 +1,17 @@
+using System.Runtime.Serialization;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonMultiMaterial
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public string id { get; set; }
+
+        [DataMember]
+        public string[] materials { get; set; }        
+    }
+}

+ 86 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonParticleSystem.cs

@@ -0,0 +1,86 @@
+using System.Runtime.Serialization;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonParticleSystem
+    {
+        [DataMember]
+        public string emitterId { get; set; }
+
+        [DataMember]
+        public float[] gravity { get; set; }
+
+        [DataMember]
+        public float[] direction1 { get; set; }
+
+        [DataMember]
+        public float[] direction2 { get; set; }
+
+        [DataMember]
+        public float[] minEmitBox { get; set; }
+
+        [DataMember]
+        public float[] maxEmitBox { get; set; }
+
+        [DataMember]
+        public float[] color1 { get; set; }
+
+        [DataMember]
+        public float[] color2 { get; set; }
+
+        [DataMember]
+        public float[] colorDead { get; set; }
+
+        [DataMember]
+        public float deadAlpha { get; set; }
+
+        [DataMember]
+        public float emitRate { get; set; }
+
+        [DataMember]
+        public float updateSpeed { get; set; }
+
+        [DataMember]
+        public int targetStopFrame { get; set; }
+
+        [DataMember]
+        public float minEmitPower { get; set; }
+
+        [DataMember]
+        public float maxEmitPower { get; set; }
+
+        [DataMember]
+        public float minLifeTime { get; set; }
+
+        [DataMember]
+        public float maxLifeTime { get; set; }
+
+        [DataMember]
+        public float minSize { get; set; }
+
+        [DataMember]
+        public float maxSize { get; set; }
+
+        [DataMember]
+        public float minAngularSpeed { get; set; }
+
+        [DataMember]
+        public float maxAngularSpeed { get; set; }
+
+        [DataMember]
+        public string textureName { get; set; }
+
+        [DataMember]
+        public int blendMode { get; set; }
+
+        [DataMember]
+        public int capacity { get; set; }
+
+        [DataMember]
+        public float[] textureMask { get; set; }
+
+        [DataMember]
+        public bool linkToEmitter { get; set; }
+    }
+}

+ 160 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonScene.cs

@@ -0,0 +1,160 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.Serialization;
+using SharpDX;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonScene
+    {
+        [DataMember]
+        public bool autoClear { get; set; }
+
+        [DataMember]
+        public float[] clearColor { get; set; }
+
+        [DataMember]
+        public float[] ambientColor { get; set; }
+
+        [DataMember]
+        public int fogMode { get; set; }
+
+        [DataMember]
+        public float[] fogColor { get; set; }
+
+        [DataMember]
+        public float fogStart { get; set; }
+
+        [DataMember]
+        public float fogEnd { get; set; }
+
+        [DataMember]
+        public float fogDensity { get; set; }
+
+        [DataMember]
+        public float[] gravity { get; set; }
+
+        [DataMember]
+        public BabylonCamera[] cameras { get; set; }
+
+        [DataMember]
+        public string activeCameraID { get; set; }
+
+        [DataMember]
+        public BabylonLight[] lights { get; set; }
+
+        [DataMember]
+        public BabylonMesh[] meshes { get; set; }
+
+        [DataMember]
+        public BabylonMaterial[] materials { get; set; }
+
+        [DataMember]
+        public BabylonMultiMaterial[] multiMaterials { get; set; }
+
+        [DataMember]
+        public BabylonParticleSystem[] particleSystems { get; set; }
+
+        [DataMember]
+        public BabylonShadowGenerator[] shadowGenerators { get; set; }
+
+        [DataMember]
+        public BabylonSkeleton[] skeletons { get; set; }
+        
+        public Vector3 MaxVector { get; set; }
+        public Vector3 MinVector { get; set; }
+
+        public string OutputPath { get; private set; }
+
+        internal List<BabylonMesh> MeshesList { get; private set; }
+        internal List<BabylonCamera> CamerasList { get; private set; }
+        internal List<BabylonLight> LightsList { get; private set; }
+        internal List<BabylonMaterial> MaterialsList { get; private set; }
+        internal List<BabylonMultiMaterial> MultiMaterialsList { get; private set; }
+        internal List<BabylonShadowGenerator> ShadowGeneratorsList { get; private set; }
+        internal List<BabylonSkeleton> SkeletonsList { get; private set; }
+
+        readonly List<string> exportedTextures = new List<string>();
+
+        public BabylonScene(string outputPath)
+        {
+            OutputPath = outputPath;
+
+            MeshesList = new List<BabylonMesh>();
+            MaterialsList = new List<BabylonMaterial>();
+            CamerasList = new List<BabylonCamera>();
+            LightsList = new List<BabylonLight>();
+            MultiMaterialsList = new List<BabylonMultiMaterial>();
+            ShadowGeneratorsList = new List<BabylonShadowGenerator>();
+            SkeletonsList = new List<BabylonSkeleton>();
+
+            // Default values
+            autoClear = true;
+            clearColor = new[] { 0.2f, 0.2f, 0.3f };
+            ambientColor = new[] {0f, 0f, 0f };
+            gravity = new[] {0f, 0f, -0.9f};
+        }
+
+        public void Prepare(bool generateDefaultLight = true)
+        {
+            meshes = MeshesList.ToArray();
+
+            materials = MaterialsList.ToArray();
+            multiMaterials = MultiMaterialsList.ToArray();
+            shadowGenerators = ShadowGeneratorsList.ToArray();
+            skeletons = SkeletonsList.ToArray();
+
+            if (CamerasList.Count == 0)
+            {
+                var camera = new BabylonCamera {name = "Default camera", id = Guid.NewGuid().ToString()};
+
+                var distanceVector = MaxVector - MinVector;
+                var midPoint = MinVector +distanceVector / 2;
+                camera.target = midPoint.ToArray();
+                camera.position = (midPoint + distanceVector).ToArray();
+
+                var distance = distanceVector.Length();
+                camera.speed =  distance/ 50.0f;
+                camera.maxZ = distance * 4f;
+
+                camera.minZ = distance < 100.0f ? 0.1f : 1.0f;
+
+                CamerasList.Add(camera);
+            }
+
+            if (LightsList.Count == 0 && generateDefaultLight)
+            {
+                var light = new BabylonLight {name = "Default light", id = Guid.NewGuid().ToString()};
+
+                var midPoint = MinVector + (MaxVector - MinVector) / 2;
+                light.type = 0;
+                light.position = (midPoint + (MaxVector - MinVector)).ToArray();
+
+                light.diffuse = new Vector3(1, 1, 1).ToArray();
+                light.specular = new Vector3(1, 1, 1).ToArray();
+
+                LightsList.Add(light);
+            }
+            
+            cameras = CamerasList.ToArray();
+            lights = LightsList.ToArray();
+
+            if (activeCameraID == null)
+            {
+                activeCameraID = CamerasList[0].id;
+            }
+        }
+
+        public void AddTexture(string diffuseTexture)
+        {
+            if (exportedTextures.Contains(diffuseTexture))
+                return;
+
+            exportedTextures.Add(diffuseTexture);
+
+            File.Copy(diffuseTexture, Path.Combine(OutputPath, Path.GetFileName(diffuseTexture)), true);
+        }
+    }
+}

+ 22 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonShadowGenerator.cs

@@ -0,0 +1,22 @@
+using System.Runtime.Serialization;
+using Vertice.Nova.Animations;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonShadowGenerator
+    {
+        [DataMember]
+        public int mapSize { get; set; }
+
+        [DataMember]
+        public string lightId { get; set; }
+
+        [DataMember]
+        public bool useVarianceShadowMap { get; set; }
+
+        [DataMember]
+        public string[] renderList { get; set; }
+
+    }
+}

+ 18 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonSkeleton.cs

@@ -0,0 +1,18 @@
+using System.Runtime.Serialization;
+using Vertice.Nova.Animations;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonSkeleton
+    {
+        [DataMember]
+        public int id { get; set; }
+        
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public BabylonBone[] bones { get; set; }
+    }
+}

+ 24 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonSubMesh.cs

@@ -0,0 +1,24 @@
+using System.Runtime.Serialization;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonSubMesh
+    {
+        [DataMember]
+        public int materialIndex { get; set; }
+
+        [DataMember]
+        public int verticesStart { get; set; }
+
+        [DataMember]
+        public int verticesCount { get; set; }
+
+        [DataMember]
+        public int indexStart { get; set; }
+
+        [DataMember]
+        public int indexCount { get; set; }
+
+    }
+}

+ 84 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Export/BabylonTexture.cs

@@ -0,0 +1,84 @@
+using System.Runtime.Serialization;
+
+namespace BabylonExport
+{
+    [DataContract]
+    public class BabylonTexture
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public float level { get; set; }
+
+        [DataMember]
+        public bool hasAlpha { get; set; }
+
+        [DataMember]
+        public int coordinatesMode { get; set; }
+        
+        [DataMember]
+        public bool isCube { get; set; }
+
+        [DataMember]
+        public float uOffset { get; set; }
+
+        [DataMember]
+        public float vOffset { get; set; }
+
+        [DataMember]
+        public float uScale { get; set; }
+
+        [DataMember]
+        public float vScale { get; set; }
+
+        [DataMember]
+        public float uAng { get; set; }
+
+        [DataMember]
+        public float vAng { get; set; }
+
+        [DataMember]
+        public float wAng { get; set; }
+
+        [DataMember]
+        public int wrapU { get; set; }
+
+        [DataMember]
+        public int wrapV { get; set; }
+
+        [DataMember]
+        public int coordinatesIndex { get; set; }
+
+        [DataMember]
+        public bool isRenderTarget { get; set; }
+
+        [DataMember]
+        public int renderTargetSize { get; set; }
+
+        [DataMember]
+        public float[] mirrorPlane { get; set; }
+
+        [DataMember]
+        public string[] renderList { get; set; }
+
+        [DataMember]
+        public BabylonAnimation[] animations { get; set; }
+        
+        public BabylonTexture()
+        {
+            level = 1.0f;
+            uOffset = 0;
+            vOffset = 0;
+            uScale = 1.0f;
+            vScale = 1.0f;
+            uAng = 0;
+            vAng = 0;
+            wAng = 0;
+            wrapU = 1;
+            wrapV = 1;
+            hasAlpha = false;
+            coordinatesIndex = 0;
+        }
+    }
+}

+ 15 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/IDumpable.cs

@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+
+namespace BabylonExport
+{
+    public interface IDumpable
+    {
+        void DumpPositions(List<float> list);
+        void DumpNormals(List<float> list);
+        void DumpUVs(List<float> list);
+        void DumpUVs2(List<float> list);
+        void DumpColors(List<float> list);
+        void DumpMatricesIndices(List<int> list);
+        void DumpMatricesWeights(List<float> list);
+    }
+}

+ 14 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/IQueryable.cs

@@ -0,0 +1,14 @@
+using SharpDX;
+
+namespace BabylonExport
+{
+    public interface IQueryable
+    {
+        bool HasWeights
+        {
+            get;
+        }
+
+        Vector3 GetPosition();
+    }
+}

+ 138 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/Mesh.cs

@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Generic;
+using BabylonExport.Exporters;
+using SharpDX;
+
+namespace BabylonExport
+{
+    public class Mesh<T> where T : struct, IDumpable, IQueryable
+    {
+        readonly List<T> vertices = new List<T>();
+        readonly List<int> indices = new List<int>();
+        string concatenatedName = "";
+
+        public Guid ID 
+        {
+            get;
+            private set;
+        }
+
+        public StandardMaterial Material { get; private set; }
+        
+        public Mesh(StandardMaterial material)
+        {
+            ID = Guid.NewGuid();
+            Material = material;
+        }
+
+        public void AddPart(string name, List<T> addedVertices, List<int> addedIndices)
+        {
+            if (concatenatedName == "")
+                concatenatedName += " / ";
+
+            concatenatedName += name;
+
+            var offset = vertices.Count;
+            vertices.AddRange(addedVertices);
+
+            foreach (int index in addedIndices)
+            {
+                indices.Add(index + offset);
+            }
+        }
+
+        public void CreateBabylonMesh(BabylonScene scene, Guid? parentID = null, BabylonSkeleton skeleton = null)
+        {
+            var babylonMesh = new BabylonMesh();
+            scene.MeshesList.Add(babylonMesh);
+
+            // Guid
+            babylonMesh.id = ID.ToString();
+
+            // Name
+            babylonMesh.name = concatenatedName;
+
+            // Parent
+            if (parentID.HasValue)
+                babylonMesh.parentId = parentID.Value.ToString();
+            else
+                babylonMesh.parentId = "";
+
+            // Material ID
+            if (Material == null)
+            {
+                babylonMesh.materialId = "";
+            }
+            else
+            {
+                babylonMesh.materialId = Material.ID.ToString();
+            }
+
+            // Skeleton ID
+            if (skeleton != null)
+            {
+                babylonMesh.skeletonId = skeleton.id;
+            }
+
+            // Position
+            babylonMesh.position = Vector3.Zero.ToArray();
+
+            // Vertices
+            var positions = new List<float>();
+            var normals = new List<float>();
+            var uvs = new List<float>();
+            var uvs2 = new List<float>();
+            var colors = new List<float>();
+            var matricesIndices = new List<int>();
+            var matricesWeights = new List<float>();
+
+            for (int index = 0; index < vertices.Count; index++)
+            {
+                var position = vertices[index].GetPosition();
+
+                scene.MinVector = Vector3.Min(scene.MinVector, position);
+                scene.MaxVector = Vector3.Max(scene.MaxVector, position);
+
+                vertices[index].DumpPositions(positions);
+                vertices[index].DumpNormals(normals);
+                vertices[index].DumpUVs(uvs);
+                vertices[index].DumpUVs2(uvs2);
+                vertices[index].DumpColors(colors);
+                vertices[index].DumpMatricesIndices(matricesIndices);
+                vertices[index].DumpMatricesWeights(matricesWeights);
+            }
+
+            if (positions.Count > 0)
+            {
+                babylonMesh.positions = positions.ToArray();
+            }
+            if (normals.Count > 0)
+            {
+                babylonMesh.normals = normals.ToArray();
+            }
+            if (uvs.Count > 0)
+            {
+                babylonMesh.uvs = uvs.ToArray();
+            }
+            if (uvs2.Count > 0)
+            {
+                babylonMesh.uvs2 = uvs2.ToArray();
+            }
+            if (colors.Count > 0)
+            {
+                babylonMesh.colors = colors.ToArray();
+            }
+            if (matricesIndices.Count > 0)
+            {
+                babylonMesh.matricesIndices = matricesIndices.ToArray();
+            }
+            if (matricesWeights.Count > 0)
+            {
+                babylonMesh.matricesWeights = matricesWeights.ToArray();
+            }
+
+            // Faces
+            babylonMesh.indices = indices.ToArray();
+        }
+    }
+}

+ 69 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/PositionNormalTextured.cs

@@ -0,0 +1,69 @@
+using System.Collections.Generic;
+using System.Globalization;
+using SharpDX;
+
+namespace BabylonExport
+{
+    public struct PositionNormalTextured : IDumpable, IQueryable
+    {
+        public const int Stride = 32;
+        public Vector3 Position;
+        public Vector3 Normal;
+        public Vector2 TextureCoordinates;
+
+        public PositionNormalTextured(Vector3 position, Vector3 normal, Vector2 textureCoordinates)
+        {
+            Position = position;
+            Normal = normal;
+            TextureCoordinates = textureCoordinates;
+        }
+
+        public override string ToString()
+        {
+            return string.Format(CultureInfo.CurrentCulture, "P:{0} N:{1} TV:{2}", Position, Normal, TextureCoordinates);
+        }
+
+        public bool HasWeights
+        {
+            get { return false; }
+        }
+
+        public Vector3 GetPosition()
+        {
+            return Position;
+        }
+
+        public void DumpPositions(List<float> list)
+        {
+            list.Add(Position.X); list.Add(Position.Y); list.Add(Position.Z);
+        }
+
+        public void DumpNormals(List<float> list)
+        {
+            Normal.Normalize();
+            list.Add(Normal.X); list.Add(Normal.Y); list.Add(Normal.Z);
+        }
+
+        public void DumpUVs(List<float> list)
+        {
+            list.Add(TextureCoordinates.X); list.Add(TextureCoordinates.Y);
+        }
+
+        public void DumpUVs2(List<float> list)
+        {
+        }
+
+        public void DumpColors(List<float> list)
+        {
+        }
+
+
+        public void DumpMatricesIndices(List<int> list)
+        {
+        }
+
+        public void DumpMatricesWeights(List<float> list)
+        {
+        }
+    }
+}

+ 75 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/PositionNormalTexturedWeights.cs

@@ -0,0 +1,75 @@
+using System.Collections.Generic;
+using System.Globalization;
+using SharpDX;
+
+namespace BabylonExport
+{
+    public struct PositionNormalTexturedWeights : IDumpable, IQueryable
+    {
+        public const int Stride = 64;
+        public Vector3 Position;
+        public int Indices;
+        public Vector4 Weights;
+        public Vector3 Normal;
+        public Vector2 TextureCoordinates;
+
+        public PositionNormalTexturedWeights(Vector3 position, Vector3 normal, Vector4 weights, int indices, Vector2 textureCoordinates)
+        {
+            Position = position;
+            Normal = normal;
+            Weights = weights;
+            Indices = indices;
+            TextureCoordinates = textureCoordinates;
+        }
+
+        public override string ToString()
+        {
+            return string.Format(CultureInfo.CurrentCulture, "P:{0} N:{1} TV:{4} W:{2} I:{3}", Position, Normal, Weights, Indices, TextureCoordinates);
+        }
+
+        public bool HasWeights
+        {
+            get { return true; }
+        }
+
+        public Vector3 GetPosition()
+        {
+            return Position;
+        }
+
+        public void DumpPositions(List<float> list)
+        {
+            list.Add(Position.X); list.Add(Position.Y); list.Add(Position.Z);
+        }
+
+        public void DumpNormals(List<float> list)
+        {
+            Normal.Normalize();
+            list.Add(Normal.X); list.Add(Normal.Y); list.Add(Normal.Z);
+        }
+
+        public void DumpUVs(List<float> list)
+        {
+            list.Add(TextureCoordinates.X); list.Add(TextureCoordinates.Y);
+        }
+
+        public void DumpUVs2(List<float> list)
+        {
+        }
+
+        public void DumpColors(List<float> list)
+        {
+        }
+
+
+        public void DumpMatricesIndices(List<int> list)
+        {
+            list.Add(Indices);
+        }
+
+        public void DumpMatricesWeights(List<float> list)
+        {
+            list.Add(Weights.X); list.Add(Weights.Y); list.Add(Weights.Z); list.Add(Weights.W);
+        }
+    }
+}

+ 42 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/ProxyMesh.cs

@@ -0,0 +1,42 @@
+using System;
+using BabylonExport.Exporters;
+using SharpDX;
+
+namespace BabylonExport
+{
+    public class ProxyMesh
+    {
+        public static Guid CreateBabylonMesh(string name, BabylonScene scene)
+        {
+            var babylonMesh = new BabylonMesh();
+            scene.MeshesList.Add(babylonMesh);
+
+            // Guid
+            var id = Guid.NewGuid();
+            babylonMesh.id = id.ToString();
+
+            // Name
+            babylonMesh.name = name;
+
+            // Parent
+            babylonMesh.parentId = "";
+
+            // Visible
+            babylonMesh.isVisible = false;
+
+            // Material ID
+            babylonMesh.materialId = "";
+
+            // Position
+            babylonMesh.position = Vector3.Zero.ToArray();
+
+            // Vertices
+            babylonMesh.positions = null;
+
+            // Faces
+            babylonMesh.indices = null;
+
+            return id;
+        }
+    }
+}

+ 76 - 0
Exporters/FBX - OBJ/BabylonExport/Entities/StandardMaterial.cs

@@ -0,0 +1,76 @@
+using System;
+using System.IO;
+using BabylonExport.Exporters;
+using SharpDX;
+
+namespace BabylonExport
+{
+    public class StandardMaterial
+    {
+        public string Name { get; set; }
+
+        public Color3 Diffuse { get; set; }
+        public Color3 Emissive { get; set; }
+        public Color3 Specular { get; set; }
+
+        public float Alpha { get; set; }
+        public float SpecularPower { get; set; }
+
+        public string DiffuseTexture { get; set; }
+
+        public bool BackFaceCulling { get; set; }
+
+        public Guid ID
+        {
+            get;
+            private set;
+        }
+
+        public StandardMaterial(string name)
+        {
+            ID = Guid.NewGuid();
+            Name = name;
+            DiffuseTexture = "";
+
+            Diffuse = new Color3(1, 1, 1);
+            Specular = new Color3(1, 1, 1);
+
+            SpecularPower = 32;
+
+            Alpha = 1.0f;
+
+            BackFaceCulling = true;
+        }
+
+        public void CreateBabylonMaterial(BabylonScene scene)
+        {
+            var babylonMaterial = new BabylonMaterial();
+            scene.MaterialsList.Add(babylonMaterial);
+
+            // Guid
+            babylonMaterial.id = ID.ToString();
+
+            // Name
+            babylonMaterial.name = Name;
+
+            // Data
+            babylonMaterial.backFaceCulling = BackFaceCulling;
+            babylonMaterial.diffuse = Diffuse.ToArray();
+            babylonMaterial.emissive = Emissive.ToArray();
+            babylonMaterial.specular = Specular.ToArray();
+            babylonMaterial.specularPower = SpecularPower;
+            babylonMaterial.alpha = Alpha;
+
+            if (string.IsNullOrEmpty(DiffuseTexture))
+            {
+                babylonMaterial.diffuseTexture = null;
+                return;
+            }
+
+            babylonMaterial.diffuseTexture = new BabylonTexture();
+            babylonMaterial.diffuseTexture.name = Path.GetFileName(DiffuseTexture);
+
+            scene.AddTexture(DiffuseTexture);
+        }
+    }
+}

+ 978 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/Blender/io_export_babylon.py

@@ -0,0 +1,978 @@
+bl_info = {
+    "name": "Babylon.js",
+    "author": "David Catuhe",
+    "version": (1, 0),
+    "blender": (2, 67, 0),
+    "location": "File > Export > Babylon.js (.babylon)",
+    "description": "Export Babylon.js scenes (.babylon)",
+    "warning": "",
+    "wiki_url": "",
+    "tracker_url": "",
+    "category": "Import-Export"}
+    
+import math
+import os
+import bpy
+import string
+import bpy_extras.io_utils
+from bpy.props import *
+import mathutils, math
+import struct
+import shutil
+from os import remove
+from bpy_extras.io_utils import (ExportHelper, axis_conversion)
+from bpy.props import (BoolProperty, FloatProperty, StringProperty, EnumProperty, FloatVectorProperty)
+from math import radians
+from mathutils import *
+
+class SubMesh:
+    materialIndex = 0
+    verticesStart = 0
+    verticesCount = 0
+    indexStart = 0
+    indexCount = 0
+    
+class MultiMaterial:
+    name = ""
+    materials = []
+
+class Export_babylon(bpy.types.Operator, ExportHelper):  
+    """Export Babylon.js scene (.babylon)""" 
+    bl_idname = "scene.babylon"
+    bl_label = "Export Babylon.js scene"
+
+    filename_ext = ".babylon"
+    filepath = ""
+    
+    # global_scale = FloatProperty(name="Scale", min=0.01, max=1000.0, default=1.0)
+
+    def execute(self, context):
+           return Export_babylon.save(self, context, **self.as_keywords(ignore=("check_existing", "filter_glob", "global_scale")))
+           
+    def mesh_triangulate(mesh):
+        try:
+            import bmesh
+            bm = bmesh.new()
+            bm.from_mesh(mesh)
+            bmesh.ops.triangulate(bm, faces=bm.faces)
+            bm.to_mesh(mesh)
+            mesh.calc_tessface()
+            bm.free()
+        except:
+            pass
+
+    def write_matrix4(file_handler, name, matrix):
+        file_handler.write(",\""+name+"\":[")
+
+        tempMatrix = matrix.copy()
+        tempMatrix.transpose()
+
+        first = True
+        for vect in tempMatrix:
+            if (first != True):
+                file_handler.write(",")
+            first = False;
+
+            file_handler.write("%.4f,%.4f,%.4f,%.4f"%(vect[0],vect[1], vect[2], vect[3]))
+                
+        file_handler.write("]")
+            
+    def write_array3(file_handler, name, array):
+        file_handler.write(",\""+name+"\":[" + "%.4f,%.4f,%.4f"%(array[0],array[1],array[2]) + "]")     
+    
+    def write_color(file_handler, name, color):
+        file_handler.write(",\""+name+"\":[" + "%.4f,%.4f,%.4f"%(color.r,color.g,color.b) + "]")
+
+    def write_vector(file_handler, name, vector):
+        file_handler.write(",\""+name+"\":[" + "%.4f,%.4f,%.4f"%(vector.x,vector.z,vector.y) + "]")
+
+    def write_vectorScaled(file_handler, name, vector, mult):
+        file_handler.write(",\""+name+"\":[" + "%.4f,%.4f,%.4f"%(vector.x * mult, vector.z * mult, vector.y * mult) + "]")
+    
+    def write_string(file_handler, name, string, noComma=False):
+        if noComma == False:
+            file_handler.write(",")
+        file_handler.write("\""+name+"\":\"" + string + "\"")
+    
+    def write_float(file_handler, name, float):
+        file_handler.write(",\""+name+"\":" + "%.4f"%(float))
+        
+    def write_int(file_handler, name, int, noComma=False):
+        if noComma == False:
+            file_handler.write(",")
+        file_handler.write("\""+name+"\":" + str(int))
+        
+    def write_bool(file_handler, name, bool, noComma=False):    
+        if noComma == False:
+            file_handler.write(",") 
+        if bool:
+            file_handler.write("\""+name+"\":" + "true")
+        else:
+            file_handler.write("\""+name+"\":" + "false")
+            
+    def getDirection(matrix):
+        return (matrix.to_3x3() * mathutils.Vector((0.0, 0.0, -1.0))).normalized()
+            
+    def export_camera(object, scene, file_handler):     
+        invWorld = object.matrix_world.copy()
+        invWorld.invert()
+        
+        target = mathutils.Vector((0, 1, 0)) * invWorld
+    
+        file_handler.write("{")
+        Export_babylon.write_string(file_handler, "name", object.name, True)        
+        Export_babylon.write_string(file_handler, "id", object.name)
+        Export_babylon.write_vector(file_handler, "position", object.location)
+        Export_babylon.write_vector(file_handler, "target", target)
+        Export_babylon.write_float(file_handler, "fov", object.data.angle)
+        Export_babylon.write_float(file_handler, "minZ", object.data.clip_start)
+        Export_babylon.write_float(file_handler, "maxZ", object.data.clip_end)
+        Export_babylon.write_float(file_handler, "speed", 1.0)
+        Export_babylon.write_float(file_handler, "inertia", 0.9)
+        Export_babylon.write_bool(file_handler, "checkCollisions", object.data.checkCollisions)
+        Export_babylon.write_bool(file_handler, "applyGravity", object.data.applyGravity)
+        Export_babylon.write_array3(file_handler, "ellipsoid", object.data.ellipsoid)
+        file_handler.write("}")
+        
+    def export_light(object, scene, file_handler):      
+        light_type_items = {'POINT': 0, 'SUN': 1, 'SPOT': 2, 'HEMI': 3, 'AREA': 0}
+        light_type = light_type_items[object.data.type]
+        
+        file_handler.write("{")
+        Export_babylon.write_string(file_handler, "name", object.name, True)        
+        Export_babylon.write_string(file_handler, "id", object.name)        
+        Export_babylon.write_float(file_handler, "type", light_type)
+        if light_type == 0:
+            Export_babylon.write_vector(file_handler, "position", object.location)
+        elif light_type == 1:
+            direction = Export_babylon.getDirection(object.matrix_world)
+            Export_babylon.write_vector(file_handler, "position", object.location)
+            Export_babylon.write_vector(file_handler, "direction", direction)
+        elif light_type == 2:
+            Export_babylon.write_vector(file_handler, "position", object.location)
+            direction = Export_babylon.getDirection(object.matrix_world)
+            Export_babylon.write_vector(file_handler, "direction", direction)
+            Export_babylon.write_float(file_handler, "angle", object.data.spot_size)
+            Export_babylon.write_float(file_handler, "exponent", object.data.spot_blend * 2)
+        else:
+            matrix_world = object.matrix_world.copy()
+            matrix_world.translation = mathutils.Vector((0, 0, 0))
+            direction = mathutils.Vector((0, 0, -1)) * matrix_world
+            Export_babylon.write_vector(file_handler, "direction", -direction)
+            Export_babylon.write_color(file_handler, "groundColor", mathutils.Color((0, 0, 0)))
+            
+        Export_babylon.write_float(file_handler, "intensity", object.data.energy)
+        
+        if object.data.use_diffuse:
+            Export_babylon.write_color(file_handler, "diffuse", object.data.color)
+        else:
+            Export_babylon.write_color(file_handler, "diffuse", mathutils.Color((0, 0, 0)))
+
+        if object.data.use_specular:
+            Export_babylon.write_color(file_handler, "specular", object.data.color)
+        else:
+            Export_babylon.write_color(file_handler, "specular", mathutils.Color((0, 0, 0)))
+            
+        file_handler.write("}")     
+    
+    def export_texture(slot, level, texture, scene, file_handler, filepath):    
+        # Copy image to output
+        try:
+            image = texture.texture.image
+            imageFilepath = os.path.normpath(bpy.path.abspath(image.filepath))
+            basename = os.path.basename(imageFilepath)
+            targetdir = os.path.dirname(filepath)
+            targetpath = os.path.join(targetdir, basename)
+            
+            if image.packed_file:
+                image.save_render(targetpath)
+            else:
+                sourcepath = bpy.path.abspath(image.filepath)
+                shutil.copy(sourcepath, targetdir)
+        except:
+            pass
+        
+        # Export
+        file_handler.write(",\""+slot+"\":{")
+        Export_babylon.write_string(file_handler, "name", basename, True)
+        Export_babylon.write_float(file_handler, "level", level)
+        Export_babylon.write_float(file_handler, "hasAlpha", texture.texture.use_alpha)
+        
+        coordinatesMode = 0;
+        if (texture.mapping == "CUBE"):
+            coordinatesMode = 3;
+        if (texture.mapping == "SPHERE"):
+            coordinatesMode = 1;        
+        Export_babylon.write_int(file_handler, "coordinatesMode", coordinatesMode)
+        Export_babylon.write_float(file_handler, "uOffset", texture.offset.x)
+        Export_babylon.write_float(file_handler, "vOffset", texture.offset.y)
+        Export_babylon.write_float(file_handler, "uScale", texture.scale.x)
+        Export_babylon.write_float(file_handler, "vScale", texture.scale.y)
+        Export_babylon.write_float(file_handler, "uAng", 0)
+        Export_babylon.write_float(file_handler, "vAng", 0)     
+        Export_babylon.write_float(file_handler, "wAng", 0)
+        
+        if (texture.texture.extension == "REPEAT"):
+            Export_babylon.write_bool(file_handler, "wrapU", True)      
+            Export_babylon.write_bool(file_handler, "wrapV", True)
+        else:
+            Export_babylon.write_bool(file_handler, "wrapU", False)     
+            Export_babylon.write_bool(file_handler, "wrapV", False)
+            
+        Export_babylon.write_int(file_handler, "coordinatesIndex", 0)
+        
+        file_handler.write("}") 
+        
+    def export_material(material, scene, file_handler, filepath):       
+        file_handler.write("{")
+        Export_babylon.write_string(file_handler, "name", material.name, True)      
+        Export_babylon.write_string(file_handler, "id", material.name)
+        Export_babylon.write_color(file_handler, "ambient", material.ambient * material.diffuse_color)
+        Export_babylon.write_color(file_handler, "diffuse", material.diffuse_intensity * material.diffuse_color)
+        Export_babylon.write_color(file_handler, "specular", material.specular_intensity * material.specular_color)
+        Export_babylon.write_float(file_handler, "specularPower", material.specular_hardness)
+        Export_babylon.write_color(file_handler, "emissive", material.emit * material.diffuse_color)        
+        Export_babylon.write_float(file_handler, "alpha", material.alpha)
+        Export_babylon.write_bool(file_handler, "backFaceCulling", material.game_settings.use_backface_culling)
+                
+        # Textures
+        for mtex in material.texture_slots:
+            if mtex and mtex.texture and mtex.texture.type == 'IMAGE':
+                if mtex.texture.image:
+                    if (mtex.use_map_color_diffuse and(mtex.texture_coords != 'REFLECTION')):
+                        # Diffuse
+                        Export_babylon.export_texture("diffuseTexture", mtex.diffuse_color_factor, mtex, scene, file_handler, filepath)
+                    if mtex.use_map_ambient:
+                        # Ambient
+                        Export_babylon.export_texture("ambientTexture", mtex.ambient_factor, mtex, scene, file_handler, filepath)
+                    if mtex.use_map_alpha:
+                        # Opacity
+                        Export_babylon.export_texture("opacityTexture", mtex.alpha_factor, mtex, scene, file_handler, filepath)
+                    if mtex.use_map_color_diffuse and (mtex.texture_coords == 'REFLECTION'):
+                        # Reflection
+                        Export_babylon.export_texture("reflectionTexture", mtex.diffuse_color_factor, mtex, scene, file_handler, filepath)
+                    if mtex.use_map_emit:
+                        # Emissive
+                        Export_babylon.export_texture("emissiveTexture", mtex.emit_factor, mtex, scene, file_handler, filepath)     
+                    if mtex.use_map_normal:
+                        # Bump
+                        Export_babylon.export_texture("bumpTexture", mtex.emit_factor, mtex, scene, file_handler, filepath)                         
+        
+        file_handler.write("}")         
+    
+    def export_multimaterial(multimaterial, scene, file_handler):       
+        file_handler.write("{")
+        Export_babylon.write_string(file_handler, "name", multimaterial.name, True)
+        Export_babylon.write_string(file_handler, "id", multimaterial.name)
+        
+        file_handler.write(",\"materials\":[")
+        first = True
+        for materialName in multimaterial.materials:
+            if first != True:
+                file_handler.write(",")
+            file_handler.write("\"" + materialName +"\"")
+            first = False
+        file_handler.write("]")
+        file_handler.write("}")
+
+    def export_animation(object, scene, file_handler, typeBl, typeBa, coma, mult):
+        if coma == True:
+            file_handler.write(",")
+        
+        file_handler.write("{")
+        Export_babylon.write_int(file_handler, "dataType", 1, True)
+        Export_babylon.write_int(file_handler, "framePerSecond", 30)
+        Export_babylon.write_int(file_handler, "loopBehavior", 1)
+        Export_babylon.write_string(file_handler, "name", typeBa+" animation")
+        Export_babylon.write_string(file_handler, "property", typeBa)
+        
+        file_handler.write(",\"keys\":[")
+            
+        frames = dict() 
+        for fcurve in object.animation_data.action.fcurves:
+            if fcurve.data_path == typeBl:
+                for key in fcurve.keyframe_points: 
+                    frame = key.co.x 
+                    frames[frame] = 1
+            
+        #for each frame (next step ==> set for key frames)
+        i = 0
+        for Frame in sorted(frames):
+            if i == 0 and Frame != 0.0:
+                file_handler.write("{")
+                Export_babylon.write_int(file_handler, "frame", 0, True)
+                bpy.context.scene.frame_set(int(Frame + bpy.context.scene.frame_start))
+                Export_babylon.write_vectorScaled(file_handler, "values", getattr(object,typeBl), mult)
+                file_handler.write("},")
+            i = i + 1
+            file_handler.write("{")
+            Export_babylon.write_int(file_handler, "frame", Frame, True)
+            bpy.context.scene.frame_set(int(Frame + bpy.context.scene.frame_start))
+            Export_babylon.write_vectorScaled(file_handler, "values", getattr(object,typeBl), mult)
+            file_handler.write("}")
+            if i != len(frames):
+                file_handler.write(",")
+            else:
+                file_handler.write(",{")
+                Export_babylon.write_int(file_handler, "frame", bpy.context.scene.frame_end - bpy.context.scene.frame_start + 1, True)
+                bpy.context.scene.frame_set(int(Frame + bpy.context.scene.frame_start))
+                Export_babylon.write_vectorScaled(file_handler, "values", getattr(object,typeBl), mult)
+                file_handler.write("}")
+        
+        file_handler.write("]}")
+
+    def export_mesh(object, scene, file_handler, multiMaterials):
+        # Get mesh  
+        mesh = object.to_mesh(scene, True, "PREVIEW")
+        
+        # Transform
+        matrix_world = object.matrix_world.copy()
+        if object.parent and object.parent.type == "ARMATURE" and len(object.vertex_groups) > 0:
+            hasSkeleton = True
+            print("skeleton", object.name)
+        else:
+            hasSkeleton = False
+            matrix_world.translation = mathutils.Vector((0, 0, 0))
+
+        mesh.transform(matrix_world)        
+                                
+        # Triangulate mesh if required
+        Export_babylon.mesh_triangulate(mesh)
+        
+        # Getting vertices and indices
+        positions=",\"positions\":["
+        normals=",\"normals\":["
+        indices=",\"indices\":["    
+
+        hasUV = True;
+        hasUV2 = True;
+        hasVertexColor = True
+
+        if len(mesh.tessface_uv_textures) > 0:
+            UVmap=mesh.tessface_uv_textures[0].data
+            uvs=",\"uvs\":["    
+        else:
+            hasUV = False
+            
+        if len(mesh.tessface_uv_textures) > 1:
+            UV2map=mesh.tessface_uv_textures[1].data
+            uvs2=",\"uvs2\":["  
+        else:
+            hasUV2 = False
+
+        if len(mesh.vertex_colors) > 0:
+            Colormap = mesh.tessface_vertex_colors.active.data
+            colors=",\"colors\":["  
+        else:
+            hasVertexColor = False
+
+        if hasSkeleton:
+            skeletonWeight = ",\"matricesWeights\":["
+            skeletonIndices = ",\"matricesIndices\":["
+            
+        alreadySavedVertices = []
+        vertices_UVs=[]
+        vertices_UV2s=[]
+        vertices_Colors=[]
+        vertices_indices=[]
+        subMeshes = []
+                
+        for v in range(0, len(mesh.vertices)):
+            alreadySavedVertices.append(False)
+            vertices_UVs.append([])
+            vertices_UV2s.append([])
+            vertices_Colors.append([])
+            vertices_indices.append([])
+                       
+        materialsCount = max(1, len(object.material_slots))
+        verticesCount = 0
+        indicesCount = 0
+
+        for materialIndex in range(materialsCount):
+            subMeshes.append(SubMesh())
+            subMeshes[materialIndex].materialIndex = materialIndex
+            subMeshes[materialIndex].verticesStart = verticesCount
+            subMeshes[materialIndex].indexStart = indicesCount
+        
+            for face in mesh.tessfaces:  # For each face
+                
+                if face.material_index != materialIndex:
+                    continue
+                
+                for v in range(3): # For each vertex in face
+                    vertex_index = face.vertices[v]
+                    vertex = mesh.vertices[vertex_index]
+                    position = vertex.co
+                    normal = vertex.normal
+
+                    #skeletons
+                    if hasSkeleton:
+                        matricesWeights = []
+                        matricesIndices = 0
+                        matricesWeights.append(0.0)
+                        matricesWeights.append(0.0)
+                        matricesWeights.append(0.0)
+                        matricesWeights.append(0.0)
+
+                        # Getting influences
+                        i = 0
+                        offset = 0
+                        for group in vertex.groups:
+                            index = group.group
+                            weight = group.weight
+
+                            for boneIndex, bone in enumerate(object.parent.pose.bones):
+                                if object.vertex_groups[index].name == bone.name:
+                                    matricesWeights[i] = weight
+                                    matricesIndices += boneIndex << offset
+                                    offset = offset + 8
+
+                                    i = i + 1
+                                    if (i == 4):
+                                        break;
+
+
+                    # Texture coordinates
+                    if hasUV:
+                        vertex_UV = UVmap[face.index].uv[v]
+                        
+                    if hasUV2:
+                        vertex_UV2 = UV2map[face.index].uv[v]
+
+                    # Vertex color
+                    if hasVertexColor:      
+                        if v == 0:              
+                            vertex_Color = Colormap[face.index].color1
+                        if v == 1:              
+                            vertex_Color = Colormap[face.index].color2
+                        if v == 2:              
+                            vertex_Color = Colormap[face.index].color3
+                        
+                    # Check if the current vertex is already saved                  
+                    alreadySaved = alreadySavedVertices[vertex_index] and not hasSkeleton
+                    if alreadySaved:
+                        alreadySaved=False                      
+                    
+                        # UV
+                        index_UV = 0
+                        for savedIndex in vertices_indices[vertex_index]:
+                            if hasUV:                                               
+                                vUV = vertices_UVs[vertex_index][index_UV]
+                                if (vUV[0]!=vertex_UV[0] or vUV[1]!=vertex_UV[1]):
+                                    continue
+
+                            if hasUV2:
+                                vUV2 = vertices_UV2s[vertex_index][index_UV]
+                                if (vUV2[0]!=vertex_UV2[0] or vUV2[1]!=vertex_UV2[1]):
+                                    continue
+
+                            if hasVertexColor:
+                                vColor = vertices_Colors[vertex_index][index_UV]
+                                if (vColor.r!=vertex_Color.r or vColor.g!=vertex_Color.g or vColor.b!=vertex_Color.b):
+                                    continue
+
+                            if vertices_indices[vertex_index][index_UV] >= subMeshes[materialIndex].verticesStart:
+                                alreadySaved=True
+                                break
+
+                            index_UV+=1                 
+
+                    if (alreadySaved):
+                        # Reuse vertex
+                        index=vertices_indices[vertex_index][index_UV]
+                    else:
+                        # Export new one
+                        index=verticesCount
+                        alreadySavedVertices[vertex_index]=True
+                        if hasUV:
+                            vertices_UVs[vertex_index].append(vertex_UV)
+                            uvs+="%.4f,%.4f,"%(vertex_UV[0], vertex_UV[1])
+                        if hasUV2:
+                            vertices_UV2s[vertex_index].append(vertex_UV2)
+                            uvs2+="%.4f,%.4f,"%(vertex_UV2[0], vertex_UV2[1])
+                        if hasVertexColor:  
+                            vertices_Colors[vertex_index].append(vertex_Color)
+                            colors+="%.4f,%.4f,%.4f,"%(vertex_Color.r,vertex_Color.g,vertex_Color.b)
+                        if hasSkeleton:
+                            skeletonWeight+="%.4f,%.4f,%.4f,%.4f,"%(matricesWeights[0], matricesWeights[1], matricesWeights[2], matricesWeights[3])
+                            skeletonIndices+="%i,"%(matricesIndices)
+
+
+                        vertices_indices[vertex_index].append(index)
+                        
+                        positions+="%.4f,%.4f,%.4f,"%(position.x,position.z,position.y)             
+                        normals+="%.4f,%.4f,%.4f,"%(normal.x,normal.z,normal.y)                     
+                        
+                        verticesCount += 1
+                    indices+="%i,"%(index)
+                    indicesCount += 1           
+                    
+            subMeshes[materialIndex].verticesCount = verticesCount - subMeshes[materialIndex].verticesStart
+            subMeshes[materialIndex].indexCount = indicesCount - subMeshes[materialIndex].indexStart
+                
+        positions=positions.rstrip(',')
+        normals=normals.rstrip(',')
+        indices=indices.rstrip(',')
+            
+        positions+="]\n"
+        normals+="]\n"
+        indices+="]\n"  
+
+        if hasUV:
+            uvs=uvs.rstrip(',')
+            uvs+="]\n"
+
+        if hasUV2:
+            uvs2=uvs.rstrip(',')
+            uvs2+="]\n"
+
+        if hasVertexColor:
+            colors=uvs.rstrip(',')
+            colors+="]\n"
+
+        if hasSkeleton:
+            skeletonWeight=skeletonWeight.rstrip(', ')
+            skeletonWeight+="]\n"
+            skeletonIndices= skeletonIndices.rstrip(', ')
+            skeletonIndices+="]\n"
+
+                
+        # Writing mesh      
+        file_handler.write("{")
+        
+        Export_babylon.write_string(file_handler, "name", object.name, True)        
+        Export_babylon.write_string(file_handler, "id", object.name)        
+        if object.parent != None:
+            Export_babylon.write_string(file_handler, "parentId", object.parent.name)
+        
+        if len(object.material_slots) == 1:
+            material = object.material_slots[0].material
+            Export_babylon.write_string(file_handler, "materialId", object.material_slots[0].name)
+            
+            if material.game_settings.face_orientation != "BILLBOARD":
+                billboardMode = 0
+            else:
+                billboardMode = 7
+        elif len(object.material_slots) > 1:
+            multimat = MultiMaterial()
+            multimat.name = "Multimaterial#" + str(len(multiMaterials))
+            Export_babylon.write_string(file_handler, "materialId", multimat.name)
+            for mat in object.material_slots:
+                multimat.materials.append(mat.name)
+                
+            multiMaterials.append(multimat)
+            billboardMode = 0
+        else:
+            billboardMode = 0
+            
+        if hasSkeleton:
+            Export_babylon.write_vector(file_handler, "position", mathutils.Vector((0, 0, 0)))
+        else:
+            Export_babylon.write_vector(file_handler, "position", object.location)
+        Export_babylon.write_vector(file_handler, "rotation", mathutils.Vector((0, 0, 0)))
+        Export_babylon.write_vector(file_handler, "scaling", mathutils.Vector((1, 1, 1)))
+        Export_babylon.write_bool(file_handler, "isVisible", object.is_visible(scene))
+        Export_babylon.write_bool(file_handler, "isEnabled", True)
+        Export_babylon.write_bool(file_handler, "checkCollisions", object.data.checkCollisions)
+        Export_babylon.write_int(file_handler, "billboardMode", billboardMode)
+        Export_babylon.write_bool(file_handler, "receiveShadows", object.data.receiveShadows)
+        if hasSkeleton:
+            i = 0
+            for obj in [object for object in scene.objects if object.is_visible(scene)]:
+                if (obj.type == 'ARMATURE'):
+                   if (obj.name == object.parent.name):
+                        Export_babylon.write_int(file_handler, "skeletonId", i)
+                   else:
+                       i = i+1
+                
+        file_handler.write(positions)
+        file_handler.write(normals)
+
+        if hasUV:
+            file_handler.write(uvs)
+
+        if hasUV2:
+            file_handler.write(uvs2)
+
+        if hasVertexColor:
+            file_handler.write(colors)
+
+        if hasSkeleton:
+            file_handler.write(skeletonWeight)
+            file_handler.write(skeletonIndices)
+
+
+        file_handler.write(indices) 
+        
+        # Sub meshes
+        file_handler.write(",\"subMeshes\":[")
+        first = True
+        for subMesh in subMeshes:
+            if first == False:
+                file_handler.write(",")
+            file_handler.write("{")
+            Export_babylon.write_int(file_handler, "materialIndex", subMesh.materialIndex, True)
+            Export_babylon.write_int(file_handler, "verticesStart", subMesh.verticesStart)
+            Export_babylon.write_int(file_handler, "verticesCount", subMesh.verticesCount)
+            Export_babylon.write_int(file_handler, "indexStart", subMesh.indexStart)
+            Export_babylon.write_int(file_handler, "indexCount", subMesh.indexCount)
+            file_handler.write("}")
+            first = False
+        file_handler.write("]")
+                
+        #Export Animations
+        
+        rotAnim = False
+        locAnim = False
+        scaAnim = False
+        coma = False
+        
+        if object.animation_data:
+            if object.animation_data.action:
+                file_handler.write(",\"animations\":[")
+                for fcurve in object.animation_data.action.fcurves:
+                    if fcurve.data_path == "rotation_euler" and rotAnim == False:
+                        Export_babylon.export_animation(object, scene, file_handler, "rotation_euler", "rotation", coma, -1)
+                        rotAnim = coma = True
+                    elif fcurve.data_path == "location" and locAnim == False:
+                        Export_babylon.export_animation(object, scene, file_handler, "location", "position", coma, 1)
+                        locAnim = coma = True
+                    elif fcurve.data_path == "scale" and scaAnim == False:
+                        Export_babylon.export_animation(object, scene, file_handler, "scale", "scaling", coma, 1)
+                        locAnim = coma = True
+                file_handler.write("]")
+                #Set Animations
+                Export_babylon.write_bool(file_handler, "autoAnimate", True)
+                Export_babylon.write_int(file_handler, "autoAnimateFrom", 0)
+                Export_babylon.write_int(file_handler, "autoAnimateTo", bpy.context.scene.frame_end - bpy.context.scene.frame_start + 1)
+                Export_babylon.write_bool(file_handler, "autoAnimateLoop", True)
+
+
+        # Closing
+        file_handler.write("}")
+        
+    def export_shadowGenerator(lamp, scene, file_handler):      
+        file_handler.write("{")
+        if lamp.data.shadowMap == 'VAR':
+            Export_babylon.write_bool(file_handler, "useVarianceShadowMap", True, True)
+        else:
+            Export_babylon.write_bool(file_handler, "useVarianceShadowMap", False, True)
+            
+        Export_babylon.write_int(file_handler, "mapSize", lamp.data.shadowMapSize)  
+        Export_babylon.write_string(file_handler, "lightId", lamp.name)     
+        
+        file_handler.write(",\"renderList\":[")
+        multiMaterials = []
+        first = True
+        for object in [object for object in scene.objects]:
+            if (object.type == 'MESH' and object.data.castShadows):
+                if first != True:
+                    file_handler.write(",")
+
+                first = False
+                file_handler.write("\"" + object.name + "\"")
+        file_handler.write("]")         
+        file_handler.write("}") 
+
+    def export_bone_matrix(armature, bone, label, file_handler):
+        SystemMatrix = Matrix.Scale(-1, 4, Vector((0, 0, 1))) * Matrix.Rotation(radians(-90), 4, 'X')
+
+        if (bone.parent):
+            Export_babylon.write_matrix4(file_handler, label, (SystemMatrix * armature.matrix_world * bone.parent.matrix).inverted() * (SystemMatrix * armature.matrix_world * bone.matrix))
+        else:
+            Export_babylon.write_matrix4(file_handler, label, SystemMatrix * armature.matrix_world * bone.matrix)
+
+
+    def export_bones(armature, scene, file_handler, id):
+        file_handler.write("{")
+
+        Export_babylon.write_string(file_handler, "name", armature.name, True)
+        Export_babylon.write_int(file_handler, "id", id)
+        
+        file_handler.write(",\"bones\":[")
+        bones = armature.pose.bones
+        first = True
+        j = 0
+        for bone in bones:
+            if first != True:
+                file_handler.write(",")
+            first = False
+
+            file_handler.write("{")
+            Export_babylon.write_string(file_handler, "name", bone.name, True)
+            Export_babylon.write_int(file_handler, "index", j)
+
+            Export_babylon.export_bone_matrix(armature, bone, "matrix", file_handler)
+
+            if (bone.parent):
+                parentId = 0
+                for parent in bones:
+                    if parent == bone.parent:
+                        break;
+                    parentId += 1
+
+                Export_babylon.write_int(file_handler, "parentBoneIndex", parentId)
+            else:
+                Export_babylon.write_int(file_handler, "parentBoneIndex", -1)
+
+            #animation
+            if (armature.animation_data.action):
+               Export_babylon.export_bonesAnimation(armature, bone, scene, file_handler)
+            
+            j = j + 1
+
+            file_handler.write("}")
+
+        file_handler.write("]")
+
+        file_handler.write("}") 
+
+    def export_bonesAnimation(armature, bone, scene, file_handler):
+        file_handler.write(",\"animation\": {")
+
+        start_frame = scene.frame_start
+        end_frame = scene.frame_end
+        fps = scene.render.fps
+
+        Export_babylon.write_int(file_handler, "dataType", 3, True)
+        Export_babylon.write_int(file_handler, "framePerSecond", fps)
+
+        #keys
+        file_handler.write(",\"keys\":[")
+                        
+        for Frame in range(start_frame, end_frame + 1):
+                
+            file_handler.write("{")
+
+            Export_babylon.write_int(file_handler, "frame", Frame, True)
+            bpy.context.scene.frame_set(Frame)
+
+            Export_babylon.export_bone_matrix(armature, bone, "values", file_handler)
+
+            if Frame == end_frame:
+                file_handler.write("}")
+            else:
+                file_handler.write("},")
+        
+        file_handler.write("]")
+            
+        Export_babylon.write_int(file_handler, "loopBehavior", 1)
+        Export_babylon.write_string(file_handler, "name", "anim")
+        Export_babylon.write_string(file_handler, "property", "_matrix")
+
+        file_handler.write("}")
+        bpy.context.scene.frame_set(start_frame)
+
+    def save(operator, context, filepath="",
+        use_apply_modifiers=False,
+        use_triangulate=True,
+        use_compress=False):
+
+        # Open file
+        file_handler = open(filepath, 'w')  
+            
+        if bpy.ops.object.mode_set.poll():
+            bpy.ops.object.mode_set(mode='OBJECT')      
+
+        # Writing scene
+        scene=context.scene
+        
+        world = scene.world
+        if world:
+            world_ambient = world.ambient_color
+        else:
+            world_ambient = Color((0.0, 0.0, 0.0))
+
+        bpy.ops.screen.animation_cancel()
+        currentFrame = bpy.context.scene.frame_current
+        bpy.context.scene.frame_set(0)
+    
+        file_handler.write("{")
+        file_handler.write("\"autoClear\":true")
+        Export_babylon.write_color(file_handler, "clearColor", world_ambient)
+        Export_babylon.write_color(file_handler, "ambientColor", world_ambient)
+        Export_babylon.write_vector(file_handler, "gravity", scene.gravity)
+        
+        if world and world.mist_settings.use_mist:
+                Export_babylon.write_int(file_handler, "fogMode", 3)
+                Export_babylon.write_color(file_handler, "fogColor", world.horizon_color)
+                Export_babylon.write_float(file_handler, "fogStart", world.mist_settings.start)
+                Export_babylon.write_float(file_handler, "fogEnd", world.mist_settings.depth)
+                Export_babylon.write_float(file_handler, "fogDensity", 0.1)
+        
+        # Cameras
+        file_handler.write(",\"cameras\":[")
+        first = True
+        for object in [object for object in scene.objects if object.is_visible(scene)]:
+            if (object.type == 'CAMERA'):
+                if first != True:
+                    file_handler.write(",")
+
+                first = False
+                data_string = Export_babylon.export_camera(object, scene, file_handler)
+        file_handler.write("]")
+                        
+        # Active camera
+        if scene.camera != None:
+            Export_babylon.write_string(file_handler, "activeCamera", scene.camera.name)
+            
+        # Lights
+        file_handler.write(",\"lights\":[")
+        first = True
+        for object in [object for object in scene.objects if object.is_visible(scene)]:
+            if (object.type == 'LAMP'):
+                if first != True:
+                    file_handler.write(",")
+
+                first = False
+                data_string = Export_babylon.export_light(object, scene, file_handler)
+        file_handler.write("]")
+        
+        # Materials
+        materials = [mat for mat in bpy.data.materials if mat.users >= 1]
+        file_handler.write(",\"materials\":[")
+        first = True
+        for material in materials:
+            if first != True:
+                file_handler.write(",")
+
+            first = False
+            data_string = Export_babylon.export_material(material, scene, file_handler, filepath)
+        file_handler.write("]")
+        
+        # Meshes
+        file_handler.write(",\"meshes\":[")
+        multiMaterials = []
+        first = True
+        for object in [object for object in scene.objects]:
+            if (object.type == 'MESH'):
+                if first != True:
+                    file_handler.write(",")
+
+                first = False
+                data_string = Export_babylon.export_mesh(object, scene, file_handler, multiMaterials)
+        file_handler.write("]")
+        
+        # Multi-materials
+        file_handler.write(",\"multiMaterials\":[")
+        first = True
+        for multimaterial in multiMaterials:
+            if first != True:
+                file_handler.write(",")
+
+            first = False
+            data_string = Export_babylon.export_multimaterial(multimaterial, scene, file_handler)
+        file_handler.write("]")
+        
+        # Shadow generators
+        file_handler.write(",\"shadowGenerators\":[")
+        first = True
+        for object in [object for object in scene.objects if object.is_visible(scene)]:
+            if (object.type == 'LAMP' and object.data.shadowMap != 'NONE'):
+                if first != True:
+                    file_handler.write(",")
+
+                first = False
+                data_string = Export_babylon.export_shadowGenerator(object, scene, file_handler)
+        file_handler.write("]")
+
+        # Armatures/Bones
+        file_handler.write(",\"skeletons\":[")
+        first = True
+        i = 0
+        for object in [object for object in scene.objects if object.is_visible(scene)]:
+            if (object.type == 'ARMATURE'):
+                if first != True:
+                    file_handler.write(",")
+
+                first = False
+                data_string = Export_babylon.export_bones(object, scene, file_handler, i)
+                i = i+1
+        file_handler.write("]")     
+        
+        # Closing
+        file_handler.write("}")
+        file_handler.close()
+
+        bpy.context.scene.frame_set(currentFrame)
+        
+        return {'FINISHED'}
+
+# UI
+bpy.types.Mesh.checkCollisions = BoolProperty(
+    name="Check Collisions", 
+    default = False)
+    
+bpy.types.Mesh.castShadows = BoolProperty(
+    name="Cast Shadows", 
+    default = False)
+    
+bpy.types.Mesh.receiveShadows = BoolProperty(
+    name="Receive Shadows", 
+    default = False)
+    
+bpy.types.Camera.checkCollisions = BoolProperty(
+    name="Check Collisions", 
+    default = False)
+    
+bpy.types.Camera.applyGravity = BoolProperty(
+    name="Apply Gravity", 
+    default = False)    
+    
+bpy.types.Camera.ellipsoid = FloatVectorProperty(
+    name="Ellipsoid", 
+    default = mathutils.Vector((0.2, 0.9, 0.2)))
+
+bpy.types.Lamp.shadowMap = EnumProperty(
+    name="Shadow Map Type", 
+    items = (('NONE', "None", "No Shadow Maps"), ('STD', "Standard", "Use Standard Shadow Maps"), ('VAR', "Variance", "Use Variance Shadow Maps")),
+    default = 'NONE')
+    
+bpy.types.Lamp.shadowMapSize = IntProperty(
+    name="Shadow Map Size", 
+    default = 512)  
+
+class ObjectPanel(bpy.types.Panel):
+    bl_label = "Babylon.js"
+    bl_space_type = "PROPERTIES"
+    bl_region_type = "WINDOW"
+    bl_context = "data"
+    
+    def draw(self, context):
+        ob = context.object
+        if not ob or not ob.data:
+            return
+            
+        layout = self.layout
+        isMesh = isinstance(ob.data, bpy.types.Mesh)
+        isCamera = isinstance(ob.data, bpy.types.Camera)
+        isLight = isinstance(ob.data, bpy.types.Lamp)
+        
+        if isMesh:
+            layout.prop(ob.data, 'checkCollisions')     
+            layout.prop(ob.data, 'castShadows')     
+            layout.prop(ob.data, 'receiveShadows')      
+        elif isCamera:
+            layout.prop(ob.data, 'checkCollisions')
+            layout.prop(ob.data, 'applyGravity')
+            layout.prop(ob.data, 'ellipsoid')
+        elif isLight:
+            layout.prop(ob.data, 'shadowMap')
+            layout.prop(ob.data, 'shadowMapSize')   
+            
+### REGISTER ###
+
+def menu_func(self, context):
+    self.layout.operator(Export_babylon.bl_idname, text="Babylon.js (.babylon)")
+
+def register():
+    bpy.utils.register_module(__name__)
+    bpy.types.INFO_MT_file_export.append(menu_func)
+
+def unregister():
+    bpy.utils.unregister_module(__name__)
+    bpy.types.INFO_MT_file_export.remove(menu_func)
+
+    
+if __name__ == "__main__":
+    register()

+ 298 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/FBXExporter.cs

@@ -0,0 +1,298 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.Serialization.Json;
+using System.Windows.Forms;
+using BabylonExport.Exporters.FBX;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using SkinnedModel;
+using Vertice.Nova.Animations;
+
+namespace BabylonExport.Exporters
+{
+    public class FBXExporter : IExporter
+    {
+        public event Action<int> OnImportProgressChanged;
+
+        readonly Dictionary<string, string> exportedTexturesFilename = new Dictionary<string, string>();
+        readonly List<StandardMaterial> exportedMaterials = new List<StandardMaterial>();
+
+        private int texturesCount = 0;
+
+        public string SupportedExtensions
+        {
+            get
+            {
+                return ".fbx";
+            }
+        }
+
+        public void GenerateBabylonFile(string file, string outputFile, bool skinned)
+        {
+            if (OnImportProgressChanged != null)
+                OnImportProgressChanged(0);
+
+
+            var scene = new BabylonScene(Path.GetDirectoryName(outputFile));
+
+            var services = new ServiceContainer();
+
+            // Create a graphics device
+            var form = new Form();
+            services.AddService<IGraphicsDeviceService>(GraphicsDeviceService.AddRef(form.Handle, 1, 1));
+
+            var contentBuilder = new ContentBuilder();
+            var contentManager = new ContentManager(services, contentBuilder.OutputDirectory);
+
+            // Tell the ContentBuilder what to build.
+            contentBuilder.Clear();
+            contentBuilder.Add(Path.GetFullPath(file), "Model", null, skinned ? "SkinnedModelProcessor" : "ModelProcessor");
+
+            // Build this new model data.
+            string buildError = contentBuilder.Build();
+
+            if (string.IsNullOrEmpty(buildError))
+            {
+                var model = contentManager.Load<Model>("Model");
+                ParseModel(model, scene);
+            }
+            else
+            {
+                throw new Exception(buildError);
+            }
+
+            // Output
+            scene.Prepare();
+            using (var outputStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write))
+            {
+                var ser = new DataContractJsonSerializer(typeof(BabylonScene));
+                ser.WriteObject(outputStream, scene);
+            }
+
+            // Cleaning
+            foreach (var path in exportedTexturesFilename.Values)
+            {
+                File.Delete(path);
+            }
+
+            if (OnImportProgressChanged != null)
+                OnImportProgressChanged(100);
+        }
+
+        void ParseModel(Model model, BabylonScene scene)
+        {
+            var effects = model.Meshes.SelectMany(m => m.Effects).ToList();
+            var meshes = model.Meshes.ToList();
+            var total = effects.Count + meshes.Count;
+            var progress = 0;
+            SkinningData skinningData = null;
+            BabylonSkeleton currentSkeleton = null;
+
+            if (model.Tag != null)
+            {
+                skinningData = model.Tag as SkinningData;
+            }
+
+            if (skinningData != null)
+            {
+                var skeleton = new BabylonSkeleton();
+                skeleton.id = scene.SkeletonsList.Count;
+                skeleton.name = "Skeleton" + scene.SkeletonsList.Count;
+                ParseBones(skinningData, skeleton);
+
+                // Animations
+                ParseAnimationClip(skinningData, skeleton);
+
+                scene.SkeletonsList.Add(skeleton);
+                currentSkeleton = skeleton;
+            }
+
+            foreach (Effect effect in effects)
+            {
+                ParseEffect(effect, scene);
+                if (OnImportProgressChanged != null)
+                    OnImportProgressChanged(((progress++) * 100) / total);
+            }
+
+            foreach (var mesh in meshes)
+            {
+                ParseMesh(mesh, scene, currentSkeleton);
+                if (OnImportProgressChanged != null)
+                    OnImportProgressChanged(((progress++) * 100) / total);
+            }
+        }
+
+        private void ParseAnimationClip(SkinningData skinningData, BabylonSkeleton skeleton)
+        {
+            foreach (var clipKey in skinningData.AnimationClips.Keys)
+            {
+                var clip = skinningData.AnimationClips[clipKey];
+                var duration = clip.Duration.TotalMilliseconds;
+                var dic = new Dictionary<int, List<BabylonAnimationKey>>();
+
+                foreach (var keyframe in clip.Keyframes)
+                {
+                    if (!dic.ContainsKey(keyframe.Bone))
+                    {
+                        dic.Add(keyframe.Bone, new List<BabylonAnimationKey>());
+                    }
+
+                    var currentTime = (float)(keyframe.Time.TotalMilliseconds * 100.0 / duration);
+
+                    dic[keyframe.Bone].Add(new BabylonAnimationKey
+                    {
+                        frame = currentTime,
+                        values = keyframe.Transform.ToMatrix().ToArray()
+                    });
+                }
+
+                foreach (var index in dic.Keys)
+                {
+                    var bone = skeleton.bones[index];
+                    var babylonAnimation = new BabylonAnimation { name = bone.name + "Animation", property = "_matrix", dataType = BabylonAnimation.DataType.Matrix, loopBehavior = InterpolationLoop.Cycle, framePerSecond = 60 };
+                    babylonAnimation.keys = dic[index].ToArray();
+                    bone.animation = babylonAnimation;
+                }
+
+                return; // Only one animation track
+            }
+        }
+
+        private void ParseBones(SkinningData skinningData, BabylonSkeleton skeleton)
+        {
+            // Bones
+            var bones = new List<BabylonBone>();
+            for (int boneIndex = 0; boneIndex < skinningData.BindPose.Count; boneIndex++)
+            {
+                var newBone = new BabylonBone();
+                bones.Add(newBone);
+
+                newBone.name = "bone" + boneIndex;
+                newBone.index = boneIndex;
+                newBone.matrix = skinningData.BindPose[boneIndex].ToMatrix().ToArray();
+                newBone.parentBoneIndex = skinningData.SkeletonHierarchy[boneIndex];
+            }
+
+            skeleton.bones = bones.ToArray();
+        }
+
+        void ParseMesh(ModelMesh modelMesh, BabylonScene scene, BabylonSkeleton skeleton)
+        {
+            var proxyID = ProxyMesh.CreateBabylonMesh(modelMesh.Name, scene);
+            int indexName = 0;
+
+            foreach (var part in modelMesh.MeshParts)
+            {
+                var material = exportedMaterials.First(m => m.Name == part.Effect.GetHashCode().ToString());
+
+                var indices = new ushort[part.PrimitiveCount * 3];
+                part.IndexBuffer.GetData(part.StartIndex * 2, indices, 0, indices.Length);
+
+                if (part.VertexBuffer.VertexDeclaration.VertexStride > PositionNormalTextured.Stride)
+                {
+                    var mesh = new Mesh<PositionNormalTexturedWeights>(material);
+                    var vertices = new PositionNormalTexturedWeights[part.NumVertices];
+
+                    part.VertexBuffer.GetData(part.VertexOffset * part.VertexBuffer.VertexDeclaration.VertexStride, vertices, 0, vertices.Length, part.VertexBuffer.VertexDeclaration.VertexStride);
+
+                    for (int index = 0; index < vertices.Length; index++)
+                    {
+                        vertices[index].TextureCoordinates.Y = 1.0f - vertices[index].TextureCoordinates.Y;
+                    }
+
+                    mesh.AddPart(indexName.ToString(), vertices.ToList(), indices.Select(i => (int)i).ToList());
+                    mesh.CreateBabylonMesh(scene, proxyID, skeleton);
+                }
+                else
+                {
+                    var mesh = new Mesh<PositionNormalTextured>(material);
+                    var vertices = new PositionNormalTextured[part.NumVertices];
+                    part.VertexBuffer.GetData(part.VertexOffset * PositionNormalTextured.Stride, vertices, 0, vertices.Length, PositionNormalTextured.Stride);
+
+                    for (int index = 0; index < vertices.Length; index++)
+                    {
+                        vertices[index].TextureCoordinates.Y = 1.0f - vertices[index].TextureCoordinates.Y;
+                    }
+
+                    mesh.AddPart(indexName.ToString(), vertices.ToList(), indices.Select(i => (int)i).ToList());
+                    mesh.CreateBabylonMesh(scene, proxyID, skeleton);
+                }
+
+                indexName++;
+            }
+        }
+
+        void ParseEffect(Effect effect, BabylonScene scene)
+        {
+            var material = new StandardMaterial(effect.GetHashCode().ToString());
+
+            exportedMaterials.Add(material);
+
+            var basicEffect = effect as BasicEffect;
+            var skinnedEffect = effect as SkinnedEffect;
+
+            if (basicEffect != null)
+            {
+                material.Alpha = basicEffect.Alpha;
+                material.Diffuse = basicEffect.DiffuseColor.ToColor3();
+                material.Emissive = basicEffect.EmissiveColor.ToColor3();
+                material.Specular = basicEffect.SpecularColor.ToColor3();
+                material.SpecularPower = basicEffect.SpecularPower;
+            }
+            else
+            {
+                material.Alpha = skinnedEffect.Alpha;
+                material.Diffuse = skinnedEffect.DiffuseColor.ToColor3();
+                material.Emissive = skinnedEffect.EmissiveColor.ToColor3();
+                material.Specular = skinnedEffect.SpecularColor.ToColor3();
+                material.SpecularPower = skinnedEffect.SpecularPower;
+            }
+
+            var texture = basicEffect != null ? basicEffect.Texture : skinnedEffect.Texture;
+
+            if (texture != null)
+            {
+                var id = texture.GetHashCode().ToString();
+
+                if (!exportedTexturesFilename.ContainsKey(id))
+                {
+                    var tempPath = Path.GetTempPath();
+                    var width = texture.Width;
+                    var height = texture.Height;
+                    string filename;
+
+                    if (texture.Format != SurfaceFormat.Dxt1)
+                    {
+                        filename = Path.Combine(tempPath, texturesCount + ".png");
+                    }
+                    else
+                    {
+                        filename = Path.Combine(tempPath, texturesCount + ".jpg");
+                    }
+
+                    texturesCount++;
+
+                    using (var file = new FileStream(filename, FileMode.Create, FileAccess.Write))
+                    {
+                        if (texture.Format != SurfaceFormat.Dxt1)
+                        {
+                            texture.SaveAsPng(file, width, height);
+                        }
+                        else
+                        {
+                            texture.SaveAsJpeg(file, width, height);
+                        }
+                    }
+
+                    exportedTexturesFilename.Add(id, filename);
+                }
+
+                material.DiffuseTexture = exportedTexturesFilename[id];
+            }
+
+            material.CreateBabylonMaterial(scene);
+        }
+    }
+}

+ 194 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/ContentBuilder.cs

@@ -0,0 +1,194 @@
+using System;
+using System.IO;
+using System.Diagnostics;
+using System.Collections.Generic;
+using Microsoft.Build.Construction;
+using Microsoft.Build.Evaluation;
+using Microsoft.Build.Execution;
+using Microsoft.Build.Framework;
+using System.Windows.Forms;
+
+namespace BabylonExport.Exporters.FBX
+{
+    class ContentBuilder : IDisposable
+    {
+        const string xnaVersion = ", Version=4.0.0.0, PublicKeyToken=842cf8be1de50553";
+
+        static readonly string[] pipelineAssemblies =
+        {
+            "Microsoft.Xna.Framework.Content.Pipeline.FBXImporter" + xnaVersion,
+            "Microsoft.Xna.Framework.Content.Pipeline.XImporter" + xnaVersion,
+            "Microsoft.Xna.Framework.Content.Pipeline.TextureImporter" + xnaVersion,
+            "Microsoft.Xna.Framework.Content.Pipeline.EffectImporter" + xnaVersion,
+            "SkinnedModelPipeline"
+        };
+
+        Project buildProject;
+        ProjectRootElement projectRootElement;
+        BuildParameters buildParameters;
+        readonly List<ProjectItem> projectItems = new List<ProjectItem>();
+        ErrorLogger errorLogger;
+
+        string buildDirectory;
+        string processDirectory;
+        string baseDirectory;
+
+        static int directorySalt;
+
+        public string OutputDirectory
+        {
+            get { return Path.Combine(buildDirectory, "bin"); }
+        }
+
+        public ContentBuilder()
+        {
+            CreateTempDirectory();
+            CreateBuildProject();
+        }
+
+        public void Dispose()
+        {
+            DeleteTempDirectory();
+        }
+
+        void CreateBuildProject()
+        {
+            string projectPath = Path.Combine(buildDirectory, "content.contentproj");
+            string outputPath = Path.Combine(buildDirectory, "bin");
+
+            // Create the build project.
+            projectRootElement = ProjectRootElement.Create(projectPath);
+
+            // Include the standard targets file that defines how to build XNA Framework content.
+            projectRootElement.AddImport(Application.StartupPath + "\\Exporters\\FBX\\XNA\\XNA Game Studio\\" +
+                                         "v4.0\\Microsoft.Xna.GameStudio.ContentPipeline.targets");
+
+            buildProject = new Project(projectRootElement);
+
+            buildProject.SetProperty("XnaPlatform", "Windows");
+            buildProject.SetProperty("XnaProfile", "Reach");
+            buildProject.SetProperty("XnaFrameworkVersion", "v4.0");
+            buildProject.SetProperty("Configuration", "Release");
+            buildProject.SetProperty("OutputPath", outputPath);
+            buildProject.SetProperty("ContentRootDirectory", ".");
+            buildProject.SetProperty("ReferencePath", Application.StartupPath);
+
+            // Register any custom importers or processors.
+            foreach (string pipelineAssembly in pipelineAssemblies)
+            {
+                buildProject.AddItem("Reference", pipelineAssembly);
+            }
+
+            // Hook up our custom error logger.
+            errorLogger = new ErrorLogger();
+
+            buildParameters = new BuildParameters(ProjectCollection.GlobalProjectCollection)
+                                  {Loggers = new ILogger[] {errorLogger}};
+        }
+
+        public void Add(string filename, string name, string importer, string processor)
+        {
+            ProjectItem item = buildProject.AddItem("Compile", filename)[0];
+
+            item.SetMetadataValue("Link", Path.GetFileName(filename));
+            item.SetMetadataValue("Name", name);
+
+            if (!string.IsNullOrEmpty(importer))
+                item.SetMetadataValue("Importer", importer);
+
+            if (!string.IsNullOrEmpty(processor))
+                item.SetMetadataValue("Processor", processor);
+
+            projectItems.Add(item);
+        }
+
+        public void Clear()
+        {
+            buildProject.RemoveItems(projectItems);
+
+            projectItems.Clear();
+        }
+
+        public string Build()
+        {
+            // Clear any previous errors.
+            errorLogger.Errors.Clear();
+
+            // Create and submit a new asynchronous build request.
+            BuildManager.DefaultBuildManager.BeginBuild(buildParameters);
+            
+            var request = new BuildRequestData(buildProject.CreateProjectInstance(), new string[0]);
+            BuildSubmission submission = BuildManager.DefaultBuildManager.PendBuildRequest(request);
+
+            submission.ExecuteAsync(null, null);
+
+            // Wait for the build to finish.
+            submission.WaitHandle.WaitOne();
+
+            BuildManager.DefaultBuildManager.EndBuild();
+
+            // If the build failed, return an error string.
+            if (submission.BuildResult.OverallResult == BuildResultCode.Failure)
+            {
+                return string.Join("\n", errorLogger.Errors.ToArray());
+            }
+
+            return null;
+        }
+
+        void CreateTempDirectory()
+        {
+            baseDirectory = Path.Combine(Path.GetTempPath(), GetType().FullName);
+            int processId = Process.GetCurrentProcess().Id;
+
+            processDirectory = Path.Combine(baseDirectory, processId.ToString());
+            directorySalt++;
+
+            buildDirectory = Path.Combine(processDirectory, directorySalt.ToString());
+
+            Directory.CreateDirectory(buildDirectory);
+
+            PurgeStaleTempDirectories();
+        }
+
+        void DeleteTempDirectory()
+        {
+            Directory.Delete(buildDirectory, true);
+
+            if (Directory.GetDirectories(processDirectory).Length == 0)
+            {
+                Directory.Delete(processDirectory);
+
+                if (Directory.GetDirectories(baseDirectory).Length == 0)
+                {
+                    Directory.Delete(baseDirectory);
+                }
+            }
+        }
+
+
+        void PurgeStaleTempDirectories()
+        {
+            // Check all subdirectories of our base location.
+            foreach (string directory in Directory.GetDirectories(baseDirectory))
+            {
+                // The subdirectory name is the ID of the process which created it.
+                int processId;
+
+                if (int.TryParse(Path.GetFileName(directory), out processId))
+                {
+                    try
+                    {
+                        // Is the creator process still running?
+                        Process.GetProcessById(processId);
+                    }
+                    catch (ArgumentException)
+                    {
+                        // If the process is gone, we can delete its temp directory.
+                        Directory.Delete(directory, true);
+                    }
+                }
+            }
+        }
+    }
+}

+ 49 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/ErrorLogger.cs

@@ -0,0 +1,49 @@
+using System.Collections.Generic;
+using Microsoft.Build.Framework;
+
+namespace BabylonExport.Exporters.FBX
+{
+    class ErrorLogger : ILogger
+    {
+        public void Initialize(IEventSource eventSource)
+        {
+            if (eventSource != null)
+            {
+                eventSource.ErrorRaised += ErrorRaised;
+            }
+        }
+
+        public void Shutdown()
+        {
+        }
+
+        void ErrorRaised(object sender, BuildErrorEventArgs e)
+        {
+            errors.Add(e.Message);
+        }
+
+        public List<string> Errors
+        {
+            get { return errors; }
+        }
+
+        List<string> errors = new List<string>();
+
+
+        string ILogger.Parameters
+        {
+            get { return parameters; }
+            set { parameters = value; }
+        }
+
+        string parameters;
+
+        LoggerVerbosity ILogger.Verbosity
+        {
+            get { return verbosity; }
+            set { verbosity = value; }
+        }
+
+        LoggerVerbosity verbosity = LoggerVerbosity.Detailed;
+    }
+}

+ 86 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/GraphicsDeviceService.cs

@@ -0,0 +1,86 @@
+using System;
+using System.Threading;
+using Microsoft.Xna.Framework.Graphics;
+
+#pragma warning disable 67
+
+namespace BabylonExport.Exporters.FBX
+{
+    class GraphicsDeviceService : IGraphicsDeviceService
+    {
+        static GraphicsDeviceService singletonInstance;
+        static int referenceCount;
+
+        GraphicsDeviceService(IntPtr windowHandle, int width, int height)
+        {
+            parameters = new PresentationParameters();
+
+            parameters.BackBufferWidth = Math.Max(width, 1);
+            parameters.BackBufferHeight = Math.Max(height, 1);
+            parameters.BackBufferFormat = SurfaceFormat.Color;
+            parameters.DepthStencilFormat = DepthFormat.Depth24;
+            parameters.DeviceWindowHandle = windowHandle;
+            parameters.PresentationInterval = PresentInterval.Immediate;
+            parameters.IsFullScreen = false;
+
+            graphicsDevice = new GraphicsDevice(GraphicsAdapter.DefaultAdapter,
+                                                GraphicsProfile.Reach,
+                                                parameters);
+        }
+
+        public static GraphicsDeviceService AddRef(IntPtr windowHandle, int width, int height)
+        {
+            if (Interlocked.Increment(ref referenceCount) == 1)
+            {
+                singletonInstance = new GraphicsDeviceService(windowHandle, width, height);
+            }
+
+            return singletonInstance;
+        }
+
+        public void Release(bool disposing)
+        {
+            if (Interlocked.Decrement(ref referenceCount) == 0)
+            {
+                if (disposing)
+                {
+                    if (DeviceDisposing != null)
+                        DeviceDisposing(this, EventArgs.Empty);
+
+                    graphicsDevice.Dispose();
+                }
+
+                graphicsDevice = null;
+            }
+        }
+
+        public void ResetDevice(int width, int height)
+        {
+            if (DeviceResetting != null)
+                DeviceResetting(this, EventArgs.Empty);
+
+            parameters.BackBufferWidth = Math.Max(parameters.BackBufferWidth, width);
+            parameters.BackBufferHeight = Math.Max(parameters.BackBufferHeight, height);
+
+            graphicsDevice.Reset(parameters);
+
+            if (DeviceReset != null)
+                DeviceReset(this, EventArgs.Empty);
+        }
+
+        
+        public GraphicsDevice GraphicsDevice
+        {
+            get { return graphicsDevice; }
+        }
+
+        GraphicsDevice graphicsDevice;
+
+        PresentationParameters parameters;
+
+        public event EventHandler<EventArgs> DeviceCreated;
+        public event EventHandler<EventArgs> DeviceDisposing;
+        public event EventHandler<EventArgs> DeviceReset;
+        public event EventHandler<EventArgs> DeviceResetting;
+    }
+}

+ 30 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/ServiceContainer.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+
+namespace BabylonExport.Exporters.FBX
+{
+    public class ServiceContainer : IServiceProvider
+    {
+        Dictionary<Type, object> services = new Dictionary<Type, object>();
+
+        /// <summary>
+        /// Adds a new service to the collection.
+        /// </summary>
+        public void AddService<T>(T service)
+        {
+            services.Add(typeof(T), service);
+        }
+
+        /// <summary>
+        /// Looks up the specified service.
+        /// </summary>
+        public object GetService(Type serviceType)
+        {
+            object service;
+
+            services.TryGetValue(serviceType, out service);
+
+            return service;
+        }
+    }
+}

+ 28 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/Microsoft.Xna.GameStudio.ContentPipelineExtensions.targets

@@ -0,0 +1,28 @@
+<!--
+***********************************************************************************************
+Microsoft.Xna.GameStudio.ContentPipelineExtensions.targets
+
+WARNING:  DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
+          created a backup copy.  Incorrect changes to this file will make it
+          impossible to load or build your projects from the command-line or the IDE.
+
+This file imports the version- and platform-specific targets for the project importing
+this file. This file also defines targets to produce an error if the specified targets
+file does not exist, but the project is built anyway (command-line or IDE build).
+
+Copyright (C) Microsoft Corporation. All rights reserved.
+***********************************************************************************************
+-->
+
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <PropertyGroup>
+    <_XnaVersionSpecificAvailablePlatforms>$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\$(XnaFrameworkVersion)\Microsoft.Xna.GameStudio.AvailablePlatforms.targets</_XnaVersionSpecificAvailablePlatforms>
+  </PropertyGroup>
+
+  <!--
+    Import the appropriate targets file, if it exists.
+  -->
+  <Import Condition="Exists('$(_XnaVersionSpecificAvailablePlatforms)')" Project="$(_XnaVersionSpecificAvailablePlatforms)" />
+
+</Project>

+ 42 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/Microsoft.Xna.GameStudio.targets

@@ -0,0 +1,42 @@
+<!--
+***********************************************************************************************
+Microsoft.Xna.GameStudio.targets
+
+WARNING:  DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
+          created a backup copy.  Incorrect changes to this file will make it
+          impossible to load or build your projects from the command-line or the IDE.
+
+This file imports the version- and platform-specific targets for the project importing
+this file. This file also defines targets to produce an error if the specified targets
+file does not exist, but the project is built anyway (command-line or IDE build).
+
+Copyright (C) Microsoft Corporation. All rights reserved.
+***********************************************************************************************
+-->
+
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <PropertyGroup>
+    <_XnaVersionSpecificImportPath>$(XnaFrameworkVersion)\</_XnaVersionSpecificImportPath>
+    <_XnaPlatformSpecificTargetsFile>Microsoft.Xna.GameStudio.$(XnaPlatform).targets</_XnaPlatformSpecificTargetsFile>
+    <_XnaPlatformSpecificTargetsPath>$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\$(_XnaVersionSpecificImportPath)$(_XnaPlatformSpecificTargetsFile)</_XnaPlatformSpecificTargetsPath>
+  </PropertyGroup>
+
+  <!--
+    If the appropriate targets file exists, it will be imported and will override
+    this target definition. If it does not exist, then this target will produce an
+    error for the user if the user attempts to build.
+  -->
+  <PropertyGroup>
+    <PrepareForBuildDependsOn Condition="!Exists('$(_XnaPlatformSpecificTargetsPath)')">UnsupportedXnaProject;$(PrepareForBuildDependsOn)</PrepareForBuildDependsOn>
+  </PropertyGroup>
+  <Target Name="UnsupportedXnaProject">
+    <Error Text="Your installation of XNA Game Studio does not support this project (XNA Platform = '$(XnaPlatform)', XNA Framework Version = '$(XnaFrameworkVersion)')." />
+  </Target>
+
+  <!--
+    Import the appropriate targets file, if it exists.
+  -->
+  <Import Condition="Exists('$(_XnaPlatformSpecificTargetsPath)')" Project="$(_XnaPlatformSpecificTargetsPath)" />
+
+</Project>

+ 57 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/AnimationClip.cs

@@ -0,0 +1,57 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// AnimationClip.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace SkinnedModel
+{
+    /// <summary>
+    /// An animation clip is the runtime equivalent of the
+    /// Microsoft.Xna.Framework.Content.Pipeline.Graphics.AnimationContent type.
+    /// It holds all the keyframes needed to describe a single animation.
+    /// </summary>
+    public class AnimationClip
+    {
+        /// <summary>
+        /// Constructs a new animation clip object.
+        /// </summary>
+        public AnimationClip(TimeSpan duration, List<Keyframe> keyframes)
+        {
+            Duration = duration;
+            Keyframes = keyframes;
+        }
+
+
+        /// <summary>
+        /// Private constructor for use by the XNB deserializer.
+        /// </summary>
+        private AnimationClip()
+        {
+        }
+
+
+        /// <summary>
+        /// Gets the total length of the animation.
+        /// </summary>
+        [ContentSerializer]
+        public TimeSpan Duration { get; private set; }
+
+
+        /// <summary>
+        /// Gets a combined list containing all the keyframes for all bones,
+        /// sorted by time.
+        /// </summary>
+        [ContentSerializer]
+        public List<Keyframe> Keyframes { get; private set; }
+    }
+}

+ 218 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/AnimationPlayer.cs

@@ -0,0 +1,218 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// AnimationPlayer.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+#endregion
+
+namespace SkinnedModel
+{
+    /// <summary>
+    /// The animation player is in charge of decoding bone position
+    /// matrices from an animation clip.
+    /// </summary>
+    public class AnimationPlayer
+    {
+        #region Fields
+
+
+        // Information about the currently playing animation clip.
+        AnimationClip currentClipValue;
+        TimeSpan currentTimeValue;
+        int currentKeyframe;
+
+
+        // Current animation transform matrices.
+        Matrix[] boneTransforms;
+        Matrix[] worldTransforms;
+        Matrix[] skinTransforms;
+
+
+        // Backlink to the bind pose and skeleton hierarchy data.
+        SkinningData skinningDataValue;
+
+
+        #endregion
+
+
+        /// <summary>
+        /// Constructs a new animation player.
+        /// </summary>
+        public AnimationPlayer(SkinningData skinningData)
+        {
+            if (skinningData == null)
+                throw new ArgumentNullException("skinningData");
+
+            skinningDataValue = skinningData;
+
+            boneTransforms = new Matrix[skinningData.BindPose.Count];
+            worldTransforms = new Matrix[skinningData.BindPose.Count];
+            skinTransforms = new Matrix[skinningData.BindPose.Count];
+        }
+
+
+        /// <summary>
+        /// Starts decoding the specified animation clip.
+        /// </summary>
+        public void StartClip(AnimationClip clip)
+        {
+            if (clip == null)
+                throw new ArgumentNullException("clip");
+
+            currentClipValue = clip;
+            currentTimeValue = TimeSpan.Zero;
+            currentKeyframe = 0;
+
+            // Initialize bone transforms to the bind pose.
+            skinningDataValue.BindPose.CopyTo(boneTransforms, 0);
+        }
+
+
+        /// <summary>
+        /// Advances the current animation position.
+        /// </summary>
+        public void Update(TimeSpan time, bool relativeToCurrentTime,
+                           Matrix rootTransform)
+        {
+            UpdateBoneTransforms(time, relativeToCurrentTime);
+            UpdateWorldTransforms(rootTransform);
+            UpdateSkinTransforms();
+        }
+
+
+        /// <summary>
+        /// Helper used by the Update method to refresh the BoneTransforms data.
+        /// </summary>
+        public void UpdateBoneTransforms(TimeSpan time, bool relativeToCurrentTime)
+        {
+            if (currentClipValue == null)
+                throw new InvalidOperationException(
+                            "AnimationPlayer.Update was called before StartClip");
+
+            // Update the animation position.
+            if (relativeToCurrentTime)
+            {
+                time += currentTimeValue;
+
+                // If we reached the end, loop back to the start.
+                while (time >= currentClipValue.Duration)
+                    time -= currentClipValue.Duration;
+            }
+
+            if ((time < TimeSpan.Zero) || (time >= currentClipValue.Duration))
+                throw new ArgumentOutOfRangeException("time");
+
+            // If the position moved backwards, reset the keyframe index.
+            if (time < currentTimeValue)
+            {
+                currentKeyframe = 0;
+                skinningDataValue.BindPose.CopyTo(boneTransforms, 0);
+            }
+
+            currentTimeValue = time;
+
+            // Read keyframe matrices.
+            IList<Keyframe> keyframes = currentClipValue.Keyframes;
+
+            while (currentKeyframe < keyframes.Count)
+            {
+                Keyframe keyframe = keyframes[currentKeyframe];
+
+                // Stop when we've read up to the current time position.
+                if (keyframe.Time > currentTimeValue)
+                    break;
+
+                // Use this keyframe.
+                boneTransforms[keyframe.Bone] = keyframe.Transform;
+
+                currentKeyframe++;
+            }
+        }
+
+
+        /// <summary>
+        /// Helper used by the Update method to refresh the WorldTransforms data.
+        /// </summary>
+        public void UpdateWorldTransforms(Matrix rootTransform)
+        {
+            // Root bone.
+            worldTransforms[0] = boneTransforms[0] * rootTransform;
+
+            // Child bones.
+            for (int bone = 1; bone < worldTransforms.Length; bone++)
+            {
+                int parentBone = skinningDataValue.SkeletonHierarchy[bone];
+
+                worldTransforms[bone] = boneTransforms[bone] *
+                                             worldTransforms[parentBone];
+            }
+        }
+
+
+        /// <summary>
+        /// Helper used by the Update method to refresh the SkinTransforms data.
+        /// </summary>
+        public void UpdateSkinTransforms()
+        {
+            for (int bone = 0; bone < skinTransforms.Length; bone++)
+            {
+                skinTransforms[bone] = skinningDataValue.InverseBindPose[bone] *
+                                            worldTransforms[bone];
+            }
+        }
+
+
+        /// <summary>
+        /// Gets the current bone transform matrices, relative to their parent bones.
+        /// </summary>
+        public Matrix[] GetBoneTransforms()
+        {
+            return boneTransforms;
+        }
+
+
+        /// <summary>
+        /// Gets the current bone transform matrices, in absolute format.
+        /// </summary>
+        public Matrix[] GetWorldTransforms()
+        {
+            return worldTransforms;
+        }
+
+
+        /// <summary>
+        /// Gets the current bone transform matrices,
+        /// relative to the skinning bind pose.
+        /// </summary>
+        public Matrix[] GetSkinTransforms()
+        {
+            return skinTransforms;
+        }
+
+
+        /// <summary>
+        /// Gets the clip currently being decoded.
+        /// </summary>
+        public AnimationClip CurrentClip
+        {
+            get { return currentClipValue; }
+        }
+
+
+        /// <summary>
+        /// Gets the current play position.
+        /// </summary>
+        public TimeSpan CurrentTime
+        {
+            get { return currentTimeValue; }
+        }
+    }
+}

BIN
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/Background.png


+ 62 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/Keyframe.cs

@@ -0,0 +1,62 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// Keyframe.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace SkinnedModel
+{
+    /// <summary>
+    /// Describes the position of a single bone at a single point in time.
+    /// </summary>
+    public class Keyframe
+    {
+        /// <summary>
+        /// Constructs a new keyframe object.
+        /// </summary>
+        public Keyframe(int bone, TimeSpan time, Matrix transform)
+        {
+            Bone = bone;
+            Time = time;
+            Transform = transform;
+        }
+
+
+        /// <summary>
+        /// Private constructor for use by the XNB deserializer.
+        /// </summary>
+        private Keyframe()
+        {
+        }
+
+
+        /// <summary>
+        /// Gets the index of the target bone that is animated by this keyframe.
+        /// </summary>
+        [ContentSerializer]
+        public int Bone { get; private set; }
+
+
+        /// <summary>
+        /// Gets the time offset from the start of the animation to this keyframe.
+        /// </summary>
+        [ContentSerializer]
+        public TimeSpan Time { get; private set; }
+
+
+        /// <summary>
+        /// Gets the bone transform for this keyframe.
+        /// </summary>
+        [ContentSerializer]
+        public Matrix Transform { get; private set; }
+    }
+}

+ 6 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/Properties/AppManifest.xml

@@ -0,0 +1,6 @@
+<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+>
+    <Deployment.Parts>
+    </Deployment.Parts>
+</Deployment>

+ 31 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/Properties/AssemblyInfo.cs

@@ -0,0 +1,31 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("SkinnedModel")]
+[assembly: AssemblyProduct("SkinnedModel")]
+[assembly: AssemblyDescription("Helper library for loading and rendering skinned character animations.")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("5e380a3c-8bce-4895-9576-cb762960c86b")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+[assembly: AssemblyVersion("1.0.0.0")]

+ 32 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/Properties/WMAppManifest.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<Deployment xmlns="http://schemas.microsoft.com/windowsphone/2009/deployment" AppPlatformVersion="7.0">
+  <App xmlns="" ProductID="{b69c5592-21a3-4b18-b70c-857cbf176bf2}" Title="SkinnedModel" RuntimeType="XNA" Version="1.0.0.0" Genre="Apps.Normal" Author="" Description="" Publisher="">
+    <IconPath IsRelative="true" IsResource="false"></IconPath>
+    <Capabilities>
+      <Capability Name="ID_CAP_NETWORKING" />
+      <Capability Name="ID_CAP_LOCATION" />
+      <Capability Name="ID_CAP_SENSORS" />
+      <Capability Name="ID_CAP_MICROPHONE" />
+      <Capability Name="ID_CAP_MEDIALIB" />
+      <Capability Name="ID_CAP_GAMERSERVICES" />
+      <Capability Name="ID_CAP_PHONEDIALER" />
+      <Capability Name="ID_CAP_PUSH_NOTIFICATION" />
+      <Capability Name="ID_CAP_WEBBROWSERCOMPONENT" />
+      <Capability Name="ID_CAP_IDENTITY_USER" />
+      <Capability Name="ID_CAP_IDENTITY_DEVICE" />
+    </Capabilities>
+    <Tasks>
+      <DefaultTask Name="_default"/>
+    </Tasks>
+    <Tokens>
+      <PrimaryToken TokenID="SkinnedModelToken" TaskName="_default">
+        <TemplateType5>
+          <BackgroundImageURI IsRelative="true" IsResource="false"></BackgroundImageURI>
+          <Count>0</Count>
+          <Title></Title>
+        </TemplateType5>
+      </PrimaryToken>
+    </Tokens>
+  </App>
+</Deployment>
+

+ 194 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/SkinnedModelWindows.csproj

@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
+  <PropertyGroup>
+    <ProjectGuid>{0D41E29B-829F-4255-BCA5-64DC2677DA6D}</ProjectGuid>
+    <ProjectTypeGuids>{6D335F3A-9D43-41b4-9D22-F6F17C4BE596};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>SkinnedModel</RootNamespace>
+    <AssemblyName>SkinnedModel</AssemblyName>
+    <XnaFrameworkVersion>v4.0</XnaFrameworkVersion>
+    <XnaPlatform>Windows</XnaPlatform>
+    <XnaCrossPlatformGroupID>caec8833-9565-4431-9a10-761f0db53497</XnaCrossPlatformGroupID>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <XnaUpgrade>
+    </XnaUpgrade>
+    <XnaOutputType>Library</XnaOutputType>
+    <XnaProfile>HiDef</XnaProfile>
+    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\x86\Debug</OutputPath>
+    <DefineConstants>DEBUG;TRACE;WINDOWS</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <NoStdLib>true</NoStdLib>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+    <PlatformTarget>x86</PlatformTarget>
+    <XnaCompressContent>false</XnaCompressContent>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\x86\Release</OutputPath>
+    <DefineConstants>TRACE%3bWINDOWS</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <NoStdLib>true</NoStdLib>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+    <PlatformTarget>x86</PlatformTarget>
+    <XnaCompressContent>True</XnaCompressContent>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|Xbox 360' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Xbox 360\Debug</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <NoStdLib>true</NoStdLib>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+    <PlatformTarget>x86</PlatformTarget>
+    <XnaCompressContent>True</XnaCompressContent>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|Xbox 360' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Xbox 360\Release</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <NoStdLib>true</NoStdLib>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+    <PlatformTarget>x86</PlatformTarget>
+    <XnaCompressContent>True</XnaCompressContent>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Avatar, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Game, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.GamerServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Input.Touch, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Net, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Storage, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Video, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=MSIL">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Xact, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="mscorlib">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <Private>False</Private>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AnimationClip.cs" />
+    <Compile Include="AnimationPlayer.cs" />
+    <Compile Include="Keyframe.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SkinningData.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Xna.Framework.3.1">
+      <Visible>False</Visible>
+      <ProductName>Microsoft XNA Framework Redistributable 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Xna.Framework.4.0">
+      <Visible>False</Visible>
+      <ProductName>Microsoft XNA Framework Redistributable 4.0</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\Microsoft.Xna.GameStudio.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 76 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModel/SkinningData.cs

@@ -0,0 +1,76 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// SkinningData.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+#endregion
+
+namespace SkinnedModel
+{
+    /// <summary>
+    /// Combines all the data needed to render and animate a skinned object.
+    /// This is typically stored in the Tag property of the Model being animated.
+    /// </summary>
+    public class SkinningData
+    {
+        /// <summary>
+        /// Constructs a new skinning data object.
+        /// </summary>
+        public SkinningData(Dictionary<string, AnimationClip> animationClips,
+                            List<Matrix> bindPose, List<Matrix> inverseBindPose,
+                            List<int> skeletonHierarchy)
+        {
+            AnimationClips = animationClips;
+            BindPose = bindPose;
+            InverseBindPose = inverseBindPose;
+            SkeletonHierarchy = skeletonHierarchy;
+        }
+
+
+        /// <summary>
+        /// Private constructor for use by the XNB deserializer.
+        /// </summary>
+        private SkinningData()
+        {
+        }
+
+
+        /// <summary>
+        /// Gets a collection of animation clips. These are stored by name in a
+        /// dictionary, so there could for instance be clips for "Walk", "Run",
+        /// "JumpReallyHigh", etc.
+        /// </summary>
+        [ContentSerializer]
+        public Dictionary<string, AnimationClip> AnimationClips { get; private set; }
+
+
+        /// <summary>
+        /// Bindpose matrices for each bone in the skeleton,
+        /// relative to the parent bone.
+        /// </summary>
+        [ContentSerializer]
+        public List<Matrix> BindPose { get; private set; }
+
+
+        /// <summary>
+        /// Vertex to bonespace transforms for each bone in the skeleton.
+        /// </summary>
+        [ContentSerializer]
+        public List<Matrix> InverseBindPose { get; private set; }
+
+
+        /// <summary>
+        /// For each bone in the skeleton, stores the index of the parent bone.
+        /// </summary>
+        [ContentSerializer]
+        public List<int> SkeletonHierarchy { get; private set; }
+    }
+}

+ 31 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModelPipeline/Properties/AssemblyInfo.cs

@@ -0,0 +1,31 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("SkinnedModelPipeline")]
+[assembly: AssemblyProduct("SkinnedModelPipeline")]
+[assembly: AssemblyDescription("Content Pipeline extension used by the Skinned Model sample.")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("004749eb-b0cf-4c1f-bdf3-390054aa0da5")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+[assembly: AssemblyVersion("1.0.0.0")]

+ 70 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModelPipeline/SkinnedModelPipeline.csproj

@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
+  <PropertyGroup>
+    <ProjectGuid>{4636C7E1-B845-4B83-B96D-64A11B8A4515}</ProjectGuid>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>SkinnedModelPipeline</RootNamespace>
+    <AssemblyName>SkinnedModelPipeline</AssemblyName>
+    <XnaFrameworkVersion>v4.0</XnaFrameworkVersion>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\x86\Debug</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <XnaPlatform>Windows</XnaPlatform>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
+      <Private>False</Private>
+      <SpecificVersion>True</SpecificVersion>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Graphics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
+      <Private>False</Private>
+      <SpecificVersion>True</SpecificVersion>
+    </Reference>
+    <Reference Include="Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553, processorArchitecture=x86">
+      <Private>False</Private>
+      <SpecificVersion>true</SpecificVersion>
+    </Reference>
+    <Reference Include="System">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System.Xml">
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>4.0</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>4.0</RequiredTargetFramework>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SkinnedModelProcessor.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\SkinnedModel\SkinnedModelWindows.csproj">
+      <Project>{0D41E29B-829F-4255-BCA5-64DC2677DA6D}</Project>
+      <Name>SkinnedModelWindows</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\Microsoft.Xna.GameStudio.ContentPipelineExtensions.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+     Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 271 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/SkinnedModelPipeline/SkinnedModelProcessor.cs

@@ -0,0 +1,271 @@
+#region File Description
+//-----------------------------------------------------------------------------
+// SkinnedModelProcessor.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+#endregion
+
+#region Using Statements
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.ComponentModel;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Content.Pipeline;
+using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
+using Microsoft.Xna.Framework.Content.Pipeline.Processors;
+using SkinnedModel;
+#endregion
+
+namespace SkinnedModelPipeline
+{
+    /// <summary>
+    /// Custom processor extends the builtin framework ModelProcessor class,
+    /// adding animation support.
+    /// </summary>
+    [ContentProcessor]
+    public class SkinnedModelProcessor : ModelProcessor
+    {
+        /// <summary>
+        /// The main Process method converts an intermediate format content pipeline
+        /// NodeContent tree to a ModelContent object with embedded animation data.
+        /// </summary>
+        public override ModelContent Process(NodeContent input,
+                                             ContentProcessorContext context)
+        {
+            ValidateMesh(input, context, null);
+
+            // Find the skeleton.
+            BoneContent skeleton = MeshHelper.FindSkeleton(input);
+
+            if (skeleton == null)
+                throw new InvalidContentException("Input skeleton not found.");
+
+            // We don't want to have to worry about different parts of the model being
+            // in different local coordinate systems, so let's just bake everything.
+            FlattenTransforms(input, skeleton);
+
+            // Read the bind pose and skeleton hierarchy data.
+            IList<BoneContent> bones = MeshHelper.FlattenSkeleton(skeleton);
+
+            if (bones.Count > SkinnedEffect.MaxBones)
+            {
+                throw new InvalidContentException(string.Format(
+                    "Skeleton has {0} bones, but the maximum supported is {1}.",
+                    bones.Count, SkinnedEffect.MaxBones));
+            }
+
+            List<Matrix> bindPose = new List<Matrix>();
+            List<Matrix> inverseBindPose = new List<Matrix>();
+            List<int> skeletonHierarchy = new List<int>();
+
+            foreach (BoneContent bone in bones)
+            {
+                bindPose.Add(bone.Transform);
+                inverseBindPose.Add(Matrix.Invert(bone.AbsoluteTransform));
+                skeletonHierarchy.Add(bones.IndexOf(bone.Parent as BoneContent));
+            }
+
+            // Convert animation data to our runtime format.
+            Dictionary<string, AnimationClip> animationClips;
+            animationClips = ProcessAnimations(skeleton.Animations, bones);
+
+            // Chain to the base ModelProcessor class so it can convert the model data.
+            ModelContent model = base.Process(input, context);
+
+            // Store our custom animation data in the Tag property of the model.
+            model.Tag = new SkinningData(animationClips, bindPose,
+                                         inverseBindPose, skeletonHierarchy);
+
+            return model;
+        }
+
+
+        /// <summary>
+        /// Converts an intermediate format content pipeline AnimationContentDictionary
+        /// object to our runtime AnimationClip format.
+        /// </summary>
+        static Dictionary<string, AnimationClip> ProcessAnimations(
+            AnimationContentDictionary animations, IList<BoneContent> bones)
+        {
+            // Build up a table mapping bone names to indices.
+            Dictionary<string, int> boneMap = new Dictionary<string, int>();
+
+            for (int i = 0; i < bones.Count; i++)
+            {
+                string boneName = bones[i].Name;
+
+                if (!string.IsNullOrEmpty(boneName))
+                    boneMap.Add(boneName, i);
+            }
+
+            // Convert each animation in turn.
+            Dictionary<string, AnimationClip> animationClips;
+            animationClips = new Dictionary<string, AnimationClip>();
+
+            foreach (KeyValuePair<string, AnimationContent> animation in animations)
+            {
+                AnimationClip processed = ProcessAnimation(animation.Value, boneMap);
+                
+                animationClips.Add(animation.Key, processed);
+            }
+
+            if (animationClips.Count == 0)
+            {
+                throw new InvalidContentException(
+                            "Input file does not contain any animations.");
+            }
+
+            return animationClips;
+        }
+
+
+        /// <summary>
+        /// Converts an intermediate format content pipeline AnimationContent
+        /// object to our runtime AnimationClip format.
+        /// </summary>
+        static AnimationClip ProcessAnimation(AnimationContent animation,
+                                              Dictionary<string, int> boneMap)
+        {
+            List<Keyframe> keyframes = new List<Keyframe>();
+
+            // For each input animation channel.
+            foreach (KeyValuePair<string, AnimationChannel> channel in
+                animation.Channels)
+            {
+                // Look up what bone this channel is controlling.
+                int boneIndex;
+
+                if (!boneMap.TryGetValue(channel.Key, out boneIndex))
+                {
+                    throw new InvalidContentException(string.Format(
+                        "Found animation for bone '{0}', " +
+                        "which is not part of the skeleton.", channel.Key));
+                }
+
+                // Convert the keyframe data.
+                foreach (AnimationKeyframe keyframe in channel.Value)
+                {
+                    keyframes.Add(new Keyframe(boneIndex, keyframe.Time,
+                                               keyframe.Transform));
+                }
+            }
+
+            // Sort the merged keyframes by time.
+            keyframes.Sort(CompareKeyframeTimes);
+
+            if (keyframes.Count == 0)
+                throw new InvalidContentException("Animation has no keyframes.");
+
+            if (animation.Duration <= TimeSpan.Zero)
+                throw new InvalidContentException("Animation has a zero duration.");
+
+            return new AnimationClip(animation.Duration, keyframes);
+        }
+
+
+        /// <summary>
+        /// Comparison function for sorting keyframes into ascending time order.
+        /// </summary>
+        static int CompareKeyframeTimes(Keyframe a, Keyframe b)
+        {
+            return a.Time.CompareTo(b.Time);
+        }
+
+
+        /// <summary>
+        /// Makes sure this mesh contains the kind of data we know how to animate.
+        /// </summary>
+        static void ValidateMesh(NodeContent node, ContentProcessorContext context,
+                                 string parentBoneName)
+        {
+            MeshContent mesh = node as MeshContent;
+
+            if (mesh != null)
+            {
+                // Validate the mesh.
+                if (parentBoneName != null)
+                {
+                    context.Logger.LogWarning(null, null,
+                        "Mesh {0} is a child of bone {1}. SkinnedModelProcessor " +
+                        "does not correctly handle meshes that are children of bones.",
+                        mesh.Name, parentBoneName);
+                }
+
+                if (!MeshHasSkinning(mesh))
+                {
+                    context.Logger.LogWarning(null, null,
+                        "Mesh {0} has no skinning information, so it has been deleted.",
+                        mesh.Name);
+
+                    mesh.Parent.Children.Remove(mesh);
+                    return;
+                }
+            }
+            else if (node is BoneContent)
+            {
+                // If this is a bone, remember that we are now looking inside it.
+                parentBoneName = node.Name;
+            }
+
+            // Recurse (iterating over a copy of the child collection,
+            // because validating children may delete some of them).
+            foreach (NodeContent child in new List<NodeContent>(node.Children))
+                ValidateMesh(child, context, parentBoneName);
+        }
+
+
+        /// <summary>
+        /// Checks whether a mesh contains skininng information.
+        /// </summary>
+        static bool MeshHasSkinning(MeshContent mesh)
+        {
+            foreach (GeometryContent geometry in mesh.Geometry)
+            {
+                if (!geometry.Vertices.Channels.Contains(VertexChannelNames.Weights()))
+                    return false;
+            }
+
+            return true;
+        }
+
+
+        /// <summary>
+        /// Bakes unwanted transforms into the model geometry,
+        /// so everything ends up in the same coordinate system.
+        /// </summary>
+        static void FlattenTransforms(NodeContent node, BoneContent skeleton)
+        {
+            foreach (NodeContent child in node.Children)
+            {
+                // Don't process the skeleton, because that is special.
+                if (child == skeleton)
+                    continue;
+
+                // Bake the local transform into the actual geometry.
+                MeshHelper.TransformScene(child, child.Transform);
+
+                // Having baked it, we can now set the local
+                // coordinate system back to identity.
+                child.Transform = Matrix.Identity;
+
+                // Recurse.
+                FlattenTransforms(child, skeleton);
+            }
+        }
+
+
+        /// <summary>
+        /// Force all the materials to use our skinned model effect.
+        /// </summary>
+        [DefaultValue(MaterialProcessorDefaultEffect.SkinnedEffect)]
+        public override MaterialProcessorDefaultEffect DefaultEffect
+        {
+            get { return MaterialProcessorDefaultEffect.SkinnedEffect; }
+            set { }
+        }
+    }
+}

BIN
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.Framework.Tools.Packaging.Tasks.dll


+ 24 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.GameStudio.AvailablePlatforms.targets

@@ -0,0 +1,24 @@
+<!--
+***********************************************************************************************
+Microsoft.Xna.GameStudio.AvailablePlatforms.targets
+
+WARNING:  DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
+          created a backup copy.  Incorrect changes to this file will make it
+          impossible to load or build your projects from the command-line or the IDE.
+
+This file defines the version-specific AvailablePlatforms property for Content Pipeline
+Extension Library (CPEL) projects. This definition makes the specified platforms available
+in the IDE's Configuration Manager. That way, upgraded CPEL projects can add new platform
+configurations if the newer version supports new platforms.
+
+Copyright (C) Microsoft Corporation. All rights reserved.
+***********************************************************************************************
+-->
+
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <PropertyGroup>
+    <AvailablePlatforms>x86,Xbox 360,Windows Phone</AvailablePlatforms>
+  </PropertyGroup>
+
+</Project>

+ 286 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.GameStudio.Common.targets

@@ -0,0 +1,286 @@
+<!--
+***********************************************************************************************
+Microsoft.Xna.GameStudio.Common.targets
+
+WARNING:  DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
+          created a backup copy.  Incorrect changes to this file will make it
+          impossible to load or build your projects from the command-line or the IDE.
+
+This file defines the steps in the standard build process specific for C# .NET projects.
+For example, it contains the step that actually calls the C# compiler.  The remainder
+of the build process is defined in Microsoft.Common.targets, which is imported by 
+this file.
+
+Copyright (C) Microsoft Corporation. All rights reserved.
+***********************************************************************************************
+-->
+
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <!-- These tasks are specific to the build process defined in this file, and are not considered general-purpose build tasks. -->
+  <UsingTask TaskName="XnaClubPackageTask" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\v4.0\Microsoft.Xna.Framework.Tools.Packaging.Tasks.dll"/>
+
+  <!--
+    If the appropriate targets file exists, it will be imported and will override
+    this target definition. If it does not exist, then this target will produce an
+    error for the user if the user attempts to build.
+  -->
+  <PropertyGroup>
+    <PrepareForBuildDependsOn Condition="'$(_XnaPlatformSpecificTargetsPath)' == ''">XnaProjectFileNeedsUpgrade;$(PrepareForBuildDependsOn)</PrepareForBuildDependsOn>
+  </PropertyGroup>
+  <Target Name="XnaProjectFileNeedsUpgrade">
+    <Error Text="The project file '$(ProjectFileName)' appears to have been created with XNA Game Studio 3.0 CTP. For instructions on how to upgrade this project to work with the current version, copy and paste this link into your browser: http://go.microsoft.com/fwlink/?LinkId=121512." />
+  </Target>
+
+  <!-- Have our package build run after the user builds the project. -->
+  <PropertyGroup>
+    <BuildDependsOn>
+      $(BuildDependsOn);
+      XNAPackageBuild;
+    </BuildDependsOn>
+  </PropertyGroup>
+
+  <!--
+    Windows platform supports C# 4.0, while non-Windows platforms currently support up to C# 3.0.
+    For Windows platform, do not alter the setting.
+    For non-Windows platforms, set it to C# 3.0 if the user has not explicitly set it to something else.
+  -->
+  <PropertyGroup Condition=" '$(XnaPlatform)' != 'Windows' ">
+    <LangVersion Condition=" '$(LangVersion)' == '' ">3</LangVersion>
+  </PropertyGroup>
+
+  <!--
+        We will not look in the TargetFrameworkDirectory for Xbox 360, nor in the GAC.
+    -->
+  <PropertyGroup>
+    <!--
+        The SearchPaths property is set to find assemblies in the following order:
+
+            (1) Files from current project - indicated by {CandidateAssemblyFiles}
+            (2) $(ReferencePath) - the reference path property, which comes from the .USER file.
+            (3) The hintpath from the referenced item itself, indicated by {HintPathFromItem}.
+            (4) The directory of MSBuild's "target" runtime from GetFrameworkPath.
+                The "target" runtime folder is the folder of the runtime that MSBuild is a part of.
+            (5) Registered assembly folders, indicated by {Registry:*,*,*}
+            (6) Legacy registered assembly folders, indicated by {AssemblyFolders}
+            (7) Look in the application's output folder (like bin\debug)
+            (8) Resolve to the GAC.
+            (9) Treat the reference's Include as if it were a real file name.
+        -->
+    <AssemblySearchPaths Condition=" '$(XnaPlatform)' != 'Windows' ">
+      {CandidateAssemblyFiles};
+      $(ReferencePath);
+      {HintPathFromItem};
+      ;
+      {Registry:$(FrameworkRegistryBase),$(XnaFrameworkVersion),$(AssemblyFoldersSuffix)};
+      ;
+      ;
+      {RawFileName};
+      $(OutputPath)
+    </AssemblySearchPaths>
+  </PropertyGroup>
+
+  <!--
+    In VS 2008, a new feature was introduced to speed up the "F5" scenario when
+    no changes have occurred. It does this by skipping the build entirely if the
+    IDE believes there are no changes. This is fast, but unreliable because it
+    does not check all the same files as msbuild does. In XNA game projects, for
+    example, the IDE does not check if any content needs to be rebuilt. As a
+    result, F5 is way faster, but you may start debugging a project that is out
+    of date. To disable the new feature, we set DisableFastUpToDateCheck to true.
+  -->
+  <PropertyGroup>
+    <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
+  </PropertyGroup>
+
+  <!--
+    The TargetFrameworkAttribute is not available in the Compact Framework.
+  -->
+  <PropertyGroup>
+    <GenerateTargetFrameworkAttribute Condition="'$(XnaPlatform)' != 'Windows'">false</GenerateTargetFrameworkAttribute>
+  </PropertyGroup>
+
+  <!--  Build the Package if the Create XNA Club Package menu was selected.  -->
+  <Target Name="XnaPackageBuild">
+
+    <XnaClubPackageTask XnaFrameworkVersion="$(XnaFrameworkVersion)" XnaPlatform="$(XnaPlatform)" ProjectPath="$(ProjectDir)" OutputPath="$(OutputPath)" AssemblyName="$(AssemblyName)" TargetExt="$(TargetExt)" ArchiveName="$(XnaArchiveName)">
+      <Output PropertyName="XnaPackageVersion" TaskParameter="XnaFrameworkVersion" />
+      <Output PropertyName="XnaPackagePlatform" TaskParameter="XnaPlatform" />
+      <Output PropertyName="XnaPackageToolPath" TaskParameter="ToolPath" />
+      <Output PropertyName="DoPackageBuild" TaskParameter="ShouldPackage" />
+      <Output PropertyName="XnaPackageThumbnail" TaskParameter="Thumbnail" />
+      <Output PropertyName="XnaPackageOutputPath" TaskParameter="OutputPath" />
+    </XnaClubPackageTask>
+
+  </Target>
+
+  <PropertyGroup>
+    <!-- Default the runtime profile to the XNA Framework version being targeted. -->
+    <XnaFrameworkRuntimeProfile Condition="'$(XnaFrameworkRuntimeProfile)'==''">$(XnaPlatform).$(XnaFrameworkVersion).$(XnaProfile)</XnaFrameworkRuntimeProfile>
+
+    <!-- Define the intermediate file into which we write the runtime profile token. -->
+    <XnaFrameworkRuntimeProfileFile Condition="'$(XnaFrameworkRuntimeProfileFile)'==''">Microsoft.Xna.Framework.RuntimeProfile.txt</XnaFrameworkRuntimeProfileFile>
+
+    <!-- Make sure our target runs before the EmbeddedResource items are processed. -->
+    <PrepareResourceNamesDependsOn>
+      EmbedXnaFrameworkRuntimeProfile;
+      $(PrepareResourceNamesDependsOn)
+    </PrepareResourceNamesDependsOn>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ToBeEmbeddedResource Include="$(IntermediateOutputPath)$(XnaFrameworkRuntimeProfileFile)">
+      <LogicalName>Microsoft.Xna.Framework.RuntimeProfile</LogicalName>
+    </ToBeEmbeddedResource>
+  </ItemGroup>
+
+  <Target Name="EmbedXnaFrameworkRuntimeProfile"
+          Condition="'$(XnaFrameworkRuntimeProfile)' != '' and '$(BuildingProject)'=='true'"
+          Inputs="$(MSBuildProjectFile)"
+          Outputs="$(IntermediateOutputPath)$(XnaFrameworkRuntimeProfileFile)" >
+
+    <CreateItem Include="$(XnaFrameworkRuntimeProfile)">
+      <Output TaskParameter="Include" ItemName="_XnaFrameworkRuntimeProfile"/>
+    </CreateItem>
+
+    <WriteLinesToFile
+      File="$(IntermediateOutputPath)$(XnaFrameworkRuntimeProfileFile)"
+      Lines="@(_XnaFrameworkRuntimeProfile)"
+      Overwrite="true"/>
+
+    <CreateItem Include="$(IntermediateOutputPath)$(XnaFrameworkRuntimeProfileFile)">
+      <Output TaskParameter="Include" ItemName="FileWrites"/>
+    </CreateItem>
+
+    <CreateItem Include="@(ToBeEmbeddedResource)">
+      <Output TaskParameter="Include" ItemName="EmbeddedResource"/>
+    </CreateItem>
+
+  </Target>
+
+
+
+  <!-- Write the cache file listing all items to be copied to the output directory. -->
+  <Target
+      Name="XnaWriteCacheFile"
+      Inputs="@(AllItemsFullPathWithTargetPath)"
+      Outputs="$(MSBuildProjectFullPath).$(Configuration).cachefile"
+      AfterTargets="GetCopyToOutputDirectoryItems">
+
+    <WriteLinesToFile File="$(MSBuildProjectFullPath).$(Configuration).cachefile"
+                      Lines="@(AllItemsFullPathWithTargetPath->'%(TargetPath)')"
+                      Overwrite="true"/>
+  </Target>
+
+
+  <!--
+    ============================================================
+                                        XNAReadDependenciesCacheFile
+
+    Reads all cache files that we output from referenced XNA projects.  
+    Cache files contain the Content files target path information, which 
+    we use to populate the manifest ItemGroup _DeploymentManifestFiles
+    ============================================================
+    -->
+
+  <PropertyGroup>
+    <GenerateManifestsDependsOn>
+      _SplitProjectReferencesByFileExistence;
+      _CopySourceItemsToOutputDirectory;
+      XNAReadDependenciesCacheFile;
+      $(GenerateManifestsDependsOn)
+    </GenerateManifestsDependsOn>
+  </PropertyGroup>
+
+  <Target
+    Name="XNAReadDependenciesCacheFile">
+
+    <CreateItem Include="%(_MSBuildProjectReferenceExistent.Identity).$(Configuration).cachefile">
+      <Output ItemName="XNADependenciesCacheFiles" TaskParameter="Include"/>
+    </CreateItem>
+
+    <ReadLinesFromFile File="%(XNADependenciesCacheFiles.Identity)"
+                       Condition="'@(XNADependenciesCacheFiles)' != ''">
+      <Output TaskParameter="Lines" ItemName="_FromBuiltDependencyContentTargetPath"/>
+    </ReadLinesFromFile>
+
+    <CreateItem Include="$(OutputPath)%(_FromBuiltDependencyContentTargetPath.Identity)"
+                AdditionalMetadata="TargetPath=%(_FromBuiltDependencyContentTargetPath.Identity);IsDataFile=false"
+                Condition="'@(_FromBuiltDependencyContentTargetPath)' != ''">
+      <Output ItemName="_DeploymentManifestFiles" TaskParameter="Include" />
+    </CreateItem>
+  </Target>
+
+  <!--
+      ============================================================
+                                          GetReferenceAssemblyPaths
+
+      Redefines the standard GetReferenceAssemblyPaths to make the original
+      target conditional on the XnaPlatform property. The original target is
+      defined below as "RealGetReferenceAssemblyPaths".
+      
+      The additional paths are specific to the desktop framework, and we do not
+      want those appended to our reference paths in non-Windows projects.
+      ============================================================
+      -->
+  <Target
+      Name="GetReferenceAssemblyPaths"
+      DependsOnTargets="RealGetReferenceAssemblyPaths">
+  </Target>
+
+  <!--
+      ============================================================
+                                          RealGetReferenceAssemblyPaths
+
+      Get the paths for the Reference Assemblies for the known versions of the
+      .NET Framework.
+
+      These paths are used by the build process in order to resolve the correct
+      assemblies from the various directories, and to support multi-targeting
+      ============================================================
+      -->
+  <Target
+      Name="RealGetReferenceAssemblyPaths"
+      DependsOnTargets="$(GetReferenceAssemblyPathsDependsOn)"
+      Condition="'$(XnaPlatform)' == 'Windows'">
+
+    <!-- if TargetFrameworkDirectory doesn't have a custom value, clear it out; that way we can get reference paths and target framework directories all in the right order -->
+    <PropertyGroup>
+      <TargetFrameworkDirectory Condition="'@(_CombinedTargetFrameworkDirectoriesItem)' == '$(TargetFrameworkDirectory)'"/>
+    </PropertyGroup>
+
+    <!-- By default if there is no root path set then the task will assume it is Program Files\Reference Assemblies\Microsoft\Framework-->
+    <GetReferenceAssemblyPaths
+        Condition="'$(TargetFrameworkMoniker)' != '' and ('$(_TargetFrameworkDirectories)' == '' or '$(_FullFrameworkReferenceAssemblyPaths)' == '')"
+        TargetFrameworkMoniker="$(TargetFrameworkMoniker)"
+        RootPath="$(TargetFrameworkRootPath)"
+        BypassFrameworkInstallChecks="$(BypassFrameworkInstallChecks)"
+          >
+      <Output TaskParameter="ReferenceAssemblyPaths" PropertyName="_TargetFrameworkDirectories"/>
+      <Output TaskParameter="FullFrameworkReferenceAssemblyPaths" PropertyName="_FullFrameworkReferenceAssemblyPaths"/>
+      <Output TaskParameter="TargetFrameworkMonikerDisplayName" PropertyName="TargetFrameworkMonikerDisplayName" Condition="'$(TargetFrameworkMonikerDisplayName)' == ''"/>
+    </GetReferenceAssemblyPaths>
+
+    <PropertyGroup>
+      <TargetFrameworkDirectory>$(_TargetFrameworkDirectories);$(TargetFrameworkDirectory);$(WinFXAssemblyDirectory)</TargetFrameworkDirectory>
+    </PropertyGroup>
+
+    <!-- Remove the AssemblyFolders if no target framework directories could be found. This is to prevent us from
+               resolving from the assemblyfolders global location if we are not acutally targeting a framework-->
+
+    <PropertyGroup>
+      <RemoveAssemblyFoldersIfNoTargetFramework Condition="'$(RemoveAssemblyFoldersIfNoTargetFramework)' == ''">true</RemoveAssemblyFoldersIfNoTargetFramework>
+    </PropertyGroup>
+
+    <PropertyGroup Condition="'$(_TargetFrameworkDirectories)' == '' and '$(AssemblySearchPaths)' != '' and '$(RemoveAssemblyFoldersIfNoTargetFramework)' == 'true'">
+      <AssemblySearchPaths>$(AssemblySearchPaths.Replace('{AssemblyFolders}', '').Split(';'))</AssemblySearchPaths>
+    </PropertyGroup>
+
+    <PropertyGroup Condition="'$(_TargetFrameworkDirectories)' == ''">
+      <TargetFrameworkProfile/>
+    </PropertyGroup>
+  </Target>
+
+
+</Project>
+

+ 343 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.GameStudio.Content.targets

@@ -0,0 +1,343 @@
+<!--
+***********************************************************************************************
+Microsoft.Xna.GameStudio.Content.targets
+
+WARNING:  DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
+          created a backup copy.  Incorrect changes to this file will make it
+          impossible to load or build your projects from the command-line or the IDE.
+
+This file defines the steps in the standard build process specific for handling nested
+XNA Game Content projects. For example, it contains the step that builds the nested content
+and copies the built content to the output directory. The remainder of the build process is
+defined in Microsoft.Common.targets, which should be imported before importing this file.
+
+Copyright (C) Microsoft Corporation. All rights reserved.
+***********************************************************************************************
+-->
+
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <!-- Have our package build run after the user builds the project. -->
+  <PropertyGroup>
+    <CoreBuildDependsOn>
+      BuildContentProjects;
+      $(CoreBuildDependsOn)
+    </CoreBuildDependsOn>
+
+    <CoreCleanDependsOn>
+      CleanContentProjects;
+      $(CoreCleanDependsOn)
+    </CoreCleanDependsOn>
+  </PropertyGroup>
+
+  <!-- Specifies the platform and profile for which content will be built,
+       in case they are not the same as the code project. -->
+  <PropertyGroup>
+    <XnaContentPlatform Condition="'$(XnaContentPlatform)' == ''" >$(XnaPlatform)</XnaContentPlatform>
+    <XnaContentProfile Condition="'$(XnaContentProfile)' == ''" >$(XnaProfile)</XnaContentProfile>
+  </PropertyGroup>
+
+  <!--
+    ============================================================
+                                        _GetContentReferences
+
+    Creates ContentReference items for ProjectReference items which
+    are content project references. Also splits referenced projects
+    into two lists: those that exist on disk and those that don't.
+    ============================================================
+    -->
+  <Target
+    Name="_GetContentReferences">
+
+    <ItemGroup>
+      <ContentReference Include="@(ProjectReference)" Condition="'%(ProjectReference.XnaReferenceType)' == 'Content'" />
+      <!-- Break the project list into two lists: those that exist on disk and those that don't. -->
+      <_MSBuildContentProjectExistent Include="@(ContentReference)" Condition="Exists('%(Identity)')" />
+      <_MSBuildContentProjectReferenceNonexistent Include="@(ContentReference)" Condition="!Exists('%(Identity)')" />
+    </ItemGroup>   
+  </Target>
+
+  <!--
+    ============================================================
+                                BeforeAssignProjectConfiguration
+    
+    Removes content project references from the ProjectReference
+    item group. This is to opt out of the assembly resolution
+    and project reference configuration processes because content
+    projects do not produce DLLs.
+    ============================================================
+    -->
+  <PropertyGroup>
+    <BeforeAssignProjectConfigurationDependsOn>
+      _GetContentReferences
+    </BeforeAssignProjectConfigurationDependsOn>
+  </PropertyGroup>
+  
+  <Target
+    Name="BeforeAssignProjectConfiguration"
+    DependsOnTargets="$(BeforeAssignProjectConfigurationDependsOn)"
+    BeforeTargets="AssignProjectConfiguration">
+    
+    <ItemGroup>
+      <ProjectReference Remove="@(ContentReference)" />
+    </ItemGroup>
+  </Target>
+
+  <!--
+    ============================================================
+                                        SetParentOutputDir
+    ============================================================
+    -->  
+  <Target
+    Name="SetParentOutputDir">
+    
+    <CreateProperty Value="$(TargetDir)">
+      <Output TaskParameter="Value" PropertyName="ParentOutputDir"/>
+    </CreateProperty>
+    <CreateProperty Value="$(MSBuildProjectDirectory)\$(IntermediateOutputPath)">
+      <Output TaskParameter="Value" PropertyName="ParentIntermediateDir"/>
+    </CreateProperty>
+  </Target>
+  
+  <!--
+    ============================================================
+                                        BuildContentProjects
+
+    Builds nested content projects to match the current platform
+    and configuration. Projects can skip this target by setting
+    SkipNestedContentBuild to true.
+    ============================================================
+    -->
+  <PropertyGroup>
+    <BuildContentProjectsDependsOn>
+      PrepareForBuild;
+      _GetContentReferences;
+      SetParentOutputDir
+    </BuildContentProjectsDependsOn>
+  </PropertyGroup>
+
+  <Target
+    Name="BuildContentProjects"
+    DependsOnTargets="$(BuildContentProjectsDependsOn)"
+    Condition="'$(SkipNestedContentBuild)'!='true'" >
+
+    <!--
+        Always build nested content projects, because the IDE and/or solution does not build them.
+        
+        The $(ContentProjectBuildTargets) will normally be blank so that the project's
+        default target is used during a P2P reference. However if a custom build process requires
+        that the referenced project has a different target to build it can be specified.
+        -->
+
+    <MSBuild
+      Projects="@(_MSBuildContentProjectExistent)"
+      BuildInParallel="true"
+      Targets="$(ContentProjectBuildTargets)"
+      Properties="Configuration=$(Configuration); Platform=$(Platform); XnaPlatform=$(XnaContentPlatform); XnaProfile=$(XnaContentProfile); ParentOutputDir=$(ParentOutputDir); ParentIntermediateDir=$(ParentIntermediateDir); ParentProjectDir=$(ProjectDir); XnaCompressContent=$(XnaCompressContent)"
+      Condition="'@(_MSBuildContentProjectExistent)'!=''">
+
+      <Output TaskParameter="TargetOutputs" ItemName="_BuiltNestedContentFiles"/>
+
+    </MSBuild>
+
+  </Target>
+
+  <!--
+    ============================================================
+                                        CleanContentProjects
+
+    Cleans nested content projects matching the current platform
+    and configuration.
+    ============================================================
+    -->
+  <PropertyGroup>
+    <CleanContentProjectsDependsOn>
+      _GetContentReferences;
+      SetParentOutputDir
+    </CleanContentProjectsDependsOn>
+  </PropertyGroup>
+  
+  <Target
+    Name="CleanContentProjects"
+    DependsOnTargets="$(CleanContentProjectsDependsOn)">
+
+    <MSBuild
+      Projects="@(_MSBuildContentProjectExistent)"
+      Targets="Clean"
+      Properties="Configuration=$(Configuration); Platform=$(Platform); XnaPlatform=$(XnaContentPlatform); XnaProfile=$(XnaContentProfile); ParentOutputDir=$(ParentOutputDir); ParentIntermediateDir=$(ParentIntermediateDir)"
+      Condition="'@(_MSBuildContentProjectExistent)'!=''" />
+
+  </Target>
+
+  <!--
+    ============================================================
+                                        GetCopyToOutputDirectoryContentProjectItems
+
+    Creates an item group of all the most-recently-built outputs
+    from the nested projects. This target is meant to be chained
+    by GetCopyToOutputDirectoryItems, so that content can be added
+    to the list of files to copy from projects referencing this
+    one.
+    
+    Also hooking into MSBuild's preexisting GetCopyToOutputDirectoryItemDependsOn
+    (which now exists as a property in MSBuild3.5, where it didn't in MSBuild 2.0)
+    ============================================================
+    -->
+
+  <PropertyGroup>
+    <GetCopyToOutputDirectoryItemsDependsOn>
+      $(GetCopyToOutputDirectoryItemsDependsOn);
+      GetCopyToOutputDirectoryContentProjectItems
+    </GetCopyToOutputDirectoryItemsDependsOn>
+  </PropertyGroup>
+  
+  <PropertyGroup>
+    <GetCopyToOutputDirectoryContentProjectItemsDependsOn>
+      _GetContentReferences;
+      SetParentOutputDir
+    </GetCopyToOutputDirectoryContentProjectItemsDependsOn>
+  </PropertyGroup>
+
+  <Target
+    Name="GetCopyToOutputDirectoryContentProjectItems"
+    DependsOnTargets="$(GetCopyToOutputDirectoryContentProjectItemsDependsOn)">
+
+    <!-- Get items from child projects first. -->
+    <MSBuild
+      Projects="@(_MSBuildContentProjectExistent)"
+      Targets="GetCopyToOutputDirectoryItems"
+      Properties="Configuration=$(Configuration); Platform=$(Platform); XnaPlatform=$(XnaContentPlatform); XnaProfile=$(XnaContentProfile); ParentOutputDir=$(ParentOutputDir); ParentIntermediateDir=$(ParentIntermediateDir)"
+      Condition="'@(_MSBuildContentProjectExistent)'!=''">
+
+      <Output TaskParameter="TargetOutputs" ItemName="_AllNestedContentProjectItemsWithTargetPath"/>
+
+    </MSBuild>
+
+    <!-- Target outputs must be full paths because they will be consumed by a different project. -->
+    <CreateItem
+      Include="@(_AllNestedContentProjectItemsWithTargetPath->'%(FullPath)')"
+      Condition="'%(_AllNestedContentProjectItemsWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(_AllNestedContentProjectItemsWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"
+                >
+      <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
+      <Output TaskParameter="Include" ItemName="_NestedContentItemsToCopyToOutputDirectoryAlways"
+              Condition="'%(_AllNestedContentProjectItemsWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
+      <Output TaskParameter="Include" ItemName="_NestedContentItemsToCopyToOutputDirectory"
+              Condition="'%(_AllNestedContentProjectItemsWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
+    </CreateItem>
+
+  </Target>
+
+  <!--
+  ============================================================
+                                      _CopySourceItemsToOutputDirectory
+  ============================================================
+  -->
+  <Target
+      Name="_CopySourceItemsToOutputDirectory"
+      DependsOnTargets="
+            GetCopyToOutputDirectoryItems;
+            _CopyOutOfDateSourceItemsToOutputDirectory;
+            _CopyOutOfDateSourceItemsToOutputDirectoryAlways;
+            GetCopyToOutputDirectoryContentProjectItems;
+            _CopyOutOfDateNestedContentItemsToOutputDirectory;
+            _CopyOutOfDateNestedContentItemsToOutputDirectoryAlways;"/>
+
+  
+
+
+  
+  <!--
+  ============================================================
+                                      _CopyOutOfDateNestedContentItemsToOutputDirectory
+
+  Copy files that have the CopyToOutputDirectory attribute set to 'PreserveNewest'.
+  ============================================================
+  -->
+  <Target
+      Name="_CopyOutOfDateNestedContentItemsToOutputDirectory"
+      Condition=" '@(_NestedContentItemsToCopyToOutputDirectory)' != '' "
+      Inputs="@(_NestedContentItemsToCopyToOutputDirectory)"
+      Outputs="@(_NestedContentItemsToCopyToOutputDirectory->'$(OutDir)%(TargetPath)')">
+
+    <!--
+    Not using SkipUnchangedFiles="true" because the application may want to change
+    one of these files and not have an incremental build replace it.
+    -->
+    <Copy
+        SourceFiles = "@(_NestedContentItemsToCopyToOutputDirectory)"
+        DestinationFiles = "@(_NestedContentItemsToCopyToOutputDirectory->'$(OutDir)%(TargetPath)')">
+
+      <Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
+
+    </Copy>
+
+  </Target>
+
+  <!--
+  ============================================================
+                                      _CopyOutOfDateNestedContentItemsToOutputDirectoryAlways
+
+  Copy files that have the CopyToOutputDirectory attribute set to 'Always'.
+  ============================================================
+  -->
+  <Target
+      Name="_CopyOutOfDateNestedContentItemsToOutputDirectoryAlways"
+      Condition=" '@(_NestedContentItemsToCopyToOutputDirectoryAlways)' != '' ">
+
+    <!--
+    Not using SkipUnchangedFiles="true" because the application may want to change
+    one of these files and not have an incremental build replace it.
+    -->
+    <Copy
+        SourceFiles = "@(_NestedContentItemsToCopyToOutputDirectoryAlways)"
+        DestinationFiles = "@(_NestedContentItemsToCopyToOutputDirectoryAlways->'$(OutDir)%(TargetPath)')">
+
+      <Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
+
+    </Copy>
+
+  </Target>
+
+
+  <!--
+    ============================================================
+                                        XNAReadContentCacheFile
+
+    Reads all cache files that we output to the intermediate path during the 
+    content build process.  Cache files contain the Content files target path 
+    information, which we use to populate the manifest ItemGroup 
+    _DeploymentManifestFiles
+    ============================================================
+    -->
+
+  <PropertyGroup>
+    <GenerateManifestsDependsOn>
+      _GetContentReferences;
+      _CopySourceItemsToOutputDirectory;
+      XNAReadContentCacheFile;
+      $(GenerateManifestsDependsOn)
+    </GenerateManifestsDependsOn>
+  </PropertyGroup>
+
+  <Target Name="XNAReadContentCacheFile">    
+    <XmlPeek XmlInputPath="%(ContentReference.Identity)" 
+             Namespaces="&lt;Namespace Prefix='msbuild' Uri='http://schemas.microsoft.com/developer/msbuild/2003'/&gt;"
+             Query="/msbuild:Project/msbuild:PropertyGroup/msbuild:ProjectGuid/text()">
+      <Output TaskParameter="Result" ItemName="ContentProjectGuid" />
+    </XmlPeek>
+    <CreateItem Include="$(MSBuildProjectDirectory)\$(IntermediateOutputPath)cachefile-%(ContentProjectGuid.Identity)-targetpath.txt">
+      <Output ItemName="XNAAllCacheFiles" TaskParameter="Include"/>
+    </CreateItem>
+    
+    <ReadLinesFromFile File="%(XNAAllCacheFiles.Identity)" 
+                       Condition="'@(XNAAllCacheFiles)' != ''">
+      <Output TaskParameter="Lines" ItemName="_FromBuiltContentTargetPath"/>
+    </ReadLinesFromFile>
+
+    <CreateItem Include="$(OutputPath)%(_FromBuiltContentTargetPath.Identity)" 
+                AdditionalMetadata="TargetPath=%(_FromBuiltContentTargetPath.Identity);IsDataFile=false"
+                Condition="'@(_FromBuiltContentTargetPath)' != ''">
+      <Output ItemName="_DeploymentManifestFiles" TaskParameter="Include" />
+    </CreateItem>
+  </Target>
+</Project>

+ 493 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.GameStudio.ContentPipeline.targets

@@ -0,0 +1,493 @@
+<!--
+***********************************************************************************************
+Microsoft.Xna.GameStudio.ContentPipeline.targets
+
+WARNING:  DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
+          created a backup copy.  Incorrect changes to this file will make it
+          impossible to load or build your projects from the command-line or the IDE.
+
+This file defines the steps in the standard content build process for XNA Game Studio projects.
+
+Copyright (C) Microsoft Corporation. All rights reserved.
+***********************************************************************************************
+-->
+
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <!-- These tasks are specific to the build process defined in this file, and are not considered general-purpose build tasks. -->
+  <UsingTask TaskName="BuildContent"      AssemblyName="Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553"/>
+  <UsingTask TaskName="BuildXact"         AssemblyName="Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553"/>
+  <UsingTask TaskName="CleanContent"      AssemblyName="Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553"/>
+  <UsingTask TaskName="GetLastOutputs"    AssemblyName="Microsoft.Xna.Framework.Content.Pipeline, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553"/>
+  
+  <!--
+    ============================================================
+                                        _BuildXNAContentLists
+
+    Build the ItemGroups of content we want to process with the
+    XNA Content Pipeline.
+    ============================================================
+    -->
+  <Target 
+    Name="_BuildXNAContentLists" 
+    Condition="'$(BuildingProject)'=='true' or '$(BuildXnaContent)' == 'true'">
+
+    <CreateItem
+      Include="@(Compile)"
+      Condition="'%(Compile.Importer)' != 'XactImporter'">
+      <Output ItemName="XNAContent" TaskParameter="Include"/>
+    </CreateItem>
+
+    <CreateItem
+      Include="@(Compile)"
+      Condition="'%(Compile.Importer)' == 'XactImporter'">
+      <Output ItemName="XACTContent" TaskParameter="Include"/>
+    </CreateItem>
+
+  </Target>
+
+  <!--
+    ============================================================
+                                        CreateManifestResourceNames
+
+    This target is required by Microsoft.Common.targets.
+    ============================================================
+    -->
+  <Target
+    Name="CreateManifestResourceNames"
+    Condition="false"
+    DependsOnTargets="$(CreateManifestResourceNamesDependsOn)"/>
+
+  <!--
+    ============================================================
+                                        CoreCompile
+
+    This target is required by Microsoft.Common.targets. It compiles
+    content using the XNA Framework Content Pipeline.
+    ============================================================
+    -->
+  <Target 
+    Name="CoreCompile"
+    DependsOnTargets="$(CoreCompileDependsOn)" 
+    Condition="'$(BuildingProject)'=='true' or '$(BuildXnaContent)' == 'true'">
+
+    <Error Condition="'$(XNAContentPipelineTargetPlatform)' == ''" Text="The XNAContentPipelineTargetPlatform property is required to build content." />
+    <Error Condition="'$(XNAContentPipelineTargetProfile)' == ''"  Text="The XNAContentPipelineTargetProfile property is required to build content." />
+    
+    <!-- Build the non-XACT content. -->
+    <BuildContent
+      BuildConfiguration="$(Configuration)"
+      IntermediateDirectory="$(ProjectDir)$(IntermediateOutputPath)"
+      OutputDirectory="$(ParentOutputDir)$(ContentRootDirectory)"
+      PipelineAssemblies="@(ReferencePath)"
+      PipelineAssemblyDependencies="@(ReferenceDependencyPaths)"
+      RebuildAll="$(XNARebuildContent)"
+      RootDirectory="$(ProjectDir)"
+      LoggerRootDirectory="$(ParentProjectDir)"
+      SourceAssets="@(XNAContent)"
+      TargetPlatform="$(XNAContentPipelineTargetPlatform)"
+      TargetProfile="$(XNAContentPipelineTargetProfile)"
+      CompressContent="$(XNACompressContent)">
+      <Output ItemName="XNAIntermediateContentFiles" TaskParameter="IntermediateFiles"/>
+      <Output ItemName="XNAOutputContentFiles" TaskParameter="OutputContentFiles"/>
+      <Output ItemName="XNARebuiltContentFiles" TaskParameter="RebuiltContentFiles"/>
+    </BuildContent>
+
+    <!-- Build the XACT content.
+    <BuildXact
+      BuildConfiguration="$(Configuration)"
+      IntermediateDirectory="$(ProjectDir)$(IntermediateOutputPath)"
+      OutputDirectory="$(ParentOutputDir)$(ContentRootDirectory)"
+      RebuildAll="$(XNARebuildContent)"
+      RootDirectory="$(ProjectDir)"
+      LoggerRootDirectory="$(ParentProjectDir)"
+      TargetPlatform="$(XNAContentPipelineTargetPlatform)"
+      TargetProfile="$(XNAContentPipelineTargetProfile)"
+      XactProjects="@(XACTContent)"
+      XnaFrameworkVersion="$(XnaFrameworkVersion)">
+      <Output ItemName="_XNAIntermediateXactFiles" TaskParameter="IntermediateFiles"/>
+      <Output ItemName="XNAIntermediateContentFiles" TaskParameter="IntermediateFiles"/>
+      <Output ItemName="XNAOutputContentFiles" TaskParameter="OutputXactFiles"/>
+      <Output ItemName="XNARebuiltContentFiles" TaskParameter="RebuiltXactFiles"/>
+      <Output ItemName="_AllBuiltXactFiles" TaskParameter="OutputXactFiles"/>
+      <Output ItemName="_AddBuiltXactFiles" TaskParameter="RebuiltXactFiles"/>
+    </BuildXact>
+
+    <AssignTargetPath
+      Files="@(_XNAIntermediateXactFiles)"
+      RootFolder="$(ProjectDir)">
+      <Output TaskParameter="AssignedFiles" ItemName="_XNAIntermediateXactFilesWithTargetPath"/>
+    </AssignTargetPath>
+
+    <CreateItem
+      Include="@(_XNAIntermediateXactFilesWithTargetPath->'%(TargetPath)')">
+      <Output TaskParameter="Include" ItemName="FileWrites"/>
+    </CreateItem>
+
+    <AssignTargetPath
+      Files="@(_AllBuiltXactFiles)"
+      RootFolder="$(ParentOutputDir)">
+      <Output TaskParameter="AssignedFiles" ItemName="_AllBuiltXactFilesWithTargetPath"/>
+    </AssignTargetPath>
+    
+    <RemoveDuplicates
+      Inputs="@(_AllBuiltXactFilesWithTargetPath->'%(TargetPath)')">
+      <Output TaskParameter="Filtered" ItemName="_AllBuiltXactFilesNoDuplicates"/>
+    </RemoveDuplicates>
+    
+    <WriteLinesToFile
+      File="$(BaseIntermediateOutputPath)$(XactOutputCacheFile)"
+      Lines="@(_AllBuiltXactFilesNoDuplicates)"
+      Overwrite="true"/>
+
+    <CreateItem
+      Include="$(BaseIntermediateOutputPath)$(XactOutputCacheFile)">
+      <Output TaskParameter="Include" ItemName="FileWrites"/>
+    </CreateItem>
+     -->
+    <!-- Items in the Content item group are not built by the XNA Framework
+         Content Pipeline. This warning is for informational purposes only,
+         but can be disabled by advanced users if custom targets have been
+         defined.
+     -->
+    <Warning
+      Condition="'@(Content)'!='' and '$(DisableContentItemWarning)'!='true'"
+      Text="Project item '%(Content.Identity)' was not built with the XNA Framework Content Pipeline. Set its Build Action property to Compile to build it."/>
+
+    <!-- Items in the EmbeddedResource item group are not supported in nested
+         content projects. This error can be disabled by advanced users if custom
+         targets have been defined.
+     -->
+    <Error
+      Condition="'@(EmbeddedResource)'!='' and '$(DisableEmbeddedResourceItemError)'!='true'"
+      Text="Project item '%(EmbeddedResource.Identity)' could not be built. Embedded Resource is not a supported Build Action for items in the Content subproject."/>
+
+
+    <!-- Begin figuring out files that should go into cache file -->
+
+    <AssignTargetPath
+      Files="@(XNAOutputContentFiles)"
+      RootFolder="$(ParentOutputDir)">
+      <Output TaskParameter="AssignedFiles" ItemName="_XNAOutputCacheFilesWithTargetPath"/>
+    </AssignTargetPath>
+
+    <!-- Grab everything marked as 'Copy always' or 'Copy if newer' 
+         Do this for files marked with build action 'None', 'Compile', and 'Content'-->
+    <CreateItem
+      Include="@(ContentWithTargetPath->'%(FullPath)')"
+      Condition="'%(ContentWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(ContentWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'">
+      <Output TaskParameter="Include" ItemName="_XNAOutputCacheFilesWithTargetPath"/>
+    </CreateItem>
+
+    <CreateItem
+      Include="@(Compile->'%(FullPath)')"
+      Condition="'%(Compile.CopyToOutputDirectory)'=='Always' or '%(Compile.CopyToOutputDirectory)'=='PreserveNewest'">
+      <Output TaskParameter="Include" ItemName="_CacheCompileItemsToCopy"/>
+    </CreateItem>
+    <AssignTargetPath Files="@(_CacheCompileItemsToCopy)" RootFolder="$(MSBuildProjectDirectory)">
+      <Output TaskParameter="AssignedFiles" ItemName="_CacheCompileItemsToCopyWithTargetPathTemp" />
+    </AssignTargetPath>
+    <CreateItem
+      Include="@(_CacheCompileItemsToCopyWithTargetPathTemp)"
+      AdditionalMetadata="TargetPath=$(ContentRootDirectoryDir)%(_CacheCompileItemsToCopyWithTargetPathTemp.TargetPath)">
+      <Output TaskParameter="Include" ItemName="_CacheCompileItemsToCopyWithTargetPath"/>
+    </CreateItem>
+    <CreateItem Include="@(_CacheCompileItemsToCopyWithTargetPath)">
+      <Output TaskParameter="Include" ItemName="_XNAOutputCacheFilesWithTargetPath"/>
+    </CreateItem>
+
+    <CreateItem
+        Include="@(_NoneWithTargetPath->'%(FullPath)')"
+        Condition="'%(_NoneWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(_NoneWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'">
+      <Output TaskParameter="Include" ItemName="_XNAOutputCacheFilesWithTargetPath"/>
+    </CreateItem>
+
+    <WriteLinesToFile
+      File="$(ParentIntermediateDir)cachefile-$(ProjectGuid)-targetpath.txt"
+      Lines="@(_XNAOutputCacheFilesWithTargetPath->'%(TargetPath)')"
+      Overwrite="true" />
+  </Target>
+
+  <!--
+    ============================================================
+                                        XNAContentClean
+
+    Clean the XNA content from the project.
+    ============================================================
+    -->
+  <Target Name="XNAContentClean">
+
+    <CleanContent
+      BuildConfiguration="$(Configuration)"
+      IntermediateDirectory="$(ProjectDir)$(IntermediateOutputPath)"
+      OutputDirectory="$(ParentOutputDir)$(ContentRootDirectory)"
+      RootDirectory="$(ProjectDir)"
+      TargetPlatform="$(XNAContentPipelineTargetPlatform)"
+      TargetProfile="$(XNAContentPipelineTargetProfile)">
+    </CleanContent>
+
+    <Delete
+      Files="$(BaseIntermediateOutputPath)$(XactOutputCacheFile)"
+      Condition="Exists('$(BaseIntermediateOutputPath)$(XactOutputCacheFile)')"
+      TreatErrorsAsWarnings="true"/>
+
+    <CreateItem Include="$(ParentIntermediateDir)cachefile-*-targetpath.txt">
+      <Output TaskParameter="Include" ItemName="_XNAContentCleanCacheFiles"/>
+    </CreateItem>
+    
+    <Delete
+      Files="@(_XNAContentCleanCacheFiles)"
+      Condition="'@(_XNAContentCleanCacheFiles)' != ''"
+      TreatErrorsAsWarnings="true" />
+  </Target>
+
+  <!--
+    ============================================================
+                                        GetBuiltContentWithTargetPaths
+
+    Gathers the built content so that it can be copied by parent
+    projects.
+    ============================================================
+    -->
+  <Target
+    Name="GetBuiltContentWithTargetPaths"
+    Outputs="@(BuiltContentWithTargetPaths)">
+
+    <GetLastOutputs
+      IntermediateDirectory="$(ProjectDir)$(IntermediateOutputPath)">
+      <Output TaskParameter="OutputContentFiles" ItemName="LastBuiltContentFiles" />
+    </GetLastOutputs>
+
+    <!-- Add metadata so only new built content is copied to the output directory. -->
+    <CreateItem
+      Include="@(LastBuiltContentFiles)"
+      AdditionalMetadata="CopyToOutputDirectory=PreserveNewest">
+      <Output TaskParameter="Include" ItemName="LastBuiltContentFilesPreserveNewest"/>
+    </CreateItem>
+    
+    <AssignTargetPath
+      Files="@(LastBuiltContentFilesPreserveNewest)"
+      RootFolder="$(ParentOutputDir)">
+      <Output TaskParameter="AssignedFiles" ItemName="BuiltContentWithTargetPaths" />
+    </AssignTargetPath>
+
+  </Target>
+
+  <!--
+    ============================================================
+                                        GetBuiltXactContentWithTargetPaths
+
+    Gathers the built XACT content so that it can be copied by
+    parent projects.
+    ============================================================
+    -->
+  <Target
+    Name="GetBuiltXactContentWithTargetPaths"
+    Outputs="@(BuiltXactContentWithTargetPaths">
+
+    <ReadLinesFromFile
+      File="$(BaseIntermediateOutputPath)$(XactOutputCacheFile)"
+      Condition="Exists('$(BaseIntermediateOutputPath)$(XactOutputCacheFile)')">
+      <Output TaskParameter="Lines" ItemName="LastBuiltXactContent"/>
+    </ReadLinesFromFile>
+
+    <!-- Add metadata so only new built content is copied to the output directory. -->
+    <CreateItem
+      Include="@(LastBuiltXactContent->'$(ParentOutputDir)%(Identity)')"
+      AdditionalMetadata="CopyToOutputDirectory=PreserveNewest">
+      <Output TaskParameter="Include" ItemName="LastBuiltXactContentPreserveNewest"/>
+    </CreateItem>
+    
+    <AssignTargetPath
+      Files="@(LastBuiltXactContentPreserveNewest)"
+      RootFolder="$(ParentOutputDir)">
+      <Output TaskParameter="AssignedFiles" ItemName="BuiltXactContentWithTargetPaths" />
+    </AssignTargetPath>
+    
+  </Target>
+  
+  <!-- Microsoft.Common.targets must be imported *before* overriding anything in it. -->
+  
+  <Import Project="$(MSBuildBinPath)\Microsoft.Common.targets" />
+  
+  <PropertyGroup>
+    <!-- This is specified as an input to CoreCompile so that msbuild recognizes a project is dirty when the targets file changes. -->
+    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\v4.0\Microsoft.Xna.GameStudio.ContentPipeline.targets</MSBuildAllProjects>
+    <!-- This is normally specified by the parent code project, but we'll define it when content is being built stand-alone. -->
+    <ParentOutputDir Condition="'$(ParentOutputDir)'==''">$(TargetDir)</ParentOutputDir>
+
+    <!-- Have our content build run when the user builds the project. -->
+    <CoreCompileDependsOn>_BuildXNAContentLists</CoreCompileDependsOn>
+
+    <!-- Have our clean targets run when the user cleans the project (also invoked by Rebuild). -->
+    <CleanDependsOn>
+      XNAContentClean;
+      $(CleanDependsOn)
+    </CleanDependsOn>
+
+    <!-- Create a property with the correct target platform for the XNA Content Pipeline BuildContent task. -->
+    <XNAContentPipelineTargetPlatform Condition="'$(XNAContentPipelineTargetPlatform)' == ''">$(XnaPlatform)</XNAContentPipelineTargetPlatform>
+    <XNAContentPipelineTargetPlatform Condition="'$(XNAContentPipelineTargetPlatform)' == 'Xbox 360'">Xbox360</XNAContentPipelineTargetPlatform>
+    <XNAContentPipelineTargetPlatform Condition="'$(XNAContentPipelineTargetPlatform)' == 'Windows Phone'">WindowsPhone</XNAContentPipelineTargetPlatform>
+
+
+    <XNAContentPipelineTargetProfile Condition="'$(XNAContentPipelineTargetProfile)' == ''">$(XnaProfile)</XNAContentPipelineTargetProfile>
+
+    <ContentRootDirectory Condition="'$(ContentRootDirectory)' == ''">$(ProjectName)</ContentRootDirectory>  <!-- Example, Content\ -->
+    <!-- Make sure this is set to String.Empty for our special case as some tasks we don't own don't like /./ in paths -->
+    <ContentRootDirectoryDir Condition="'$(ContentRootDirectoryDir)' == '' and '$(ContentRootDirectory)' != '.'">$(ContentRootDirectory)</ContentRootDirectoryDir>
+    <!-- Ensure ContentDir has a trailing slash, so it can be concatenated -->
+    <ContentRootDirectoryDir Condition="'$(ContentRootDirectoryDir)' != '' and !HasTrailingSlash('$(ContentRootDirectoryDir)')">$(ContentRootDirectory)\</ContentRootDirectoryDir>
+
+    <XactOutputCacheFile Condition="'$(XactOutputCacheFile)'==''">$(MSBuildProjectFile).XactOutput.FileList.txt</XactOutputCacheFile>
+
+    <!-- AvailablePlatforms is the list of platform targets available. -->
+    <AvailablePlatforms>Xbox 360,x86,Windows Phone</AvailablePlatforms>
+  </PropertyGroup>
+
+  <!--
+    ============================================================
+                                        AssignTargetPaths
+
+    This target creates <TargetPath> tags for items. <TargetPath> is a relative folder plus filename
+    for the destination of this item. Overridden so that the nested project's source items can be
+    copied to the output directory.
+    ============================================================
+    -->
+  <Target
+      Name="AssignTargetPaths">
+
+    <AssignTargetPath Files="@(Content)" RootFolder="$(MSBuildProjectDirectory)">
+      <Output TaskParameter="AssignedFiles" ItemName="ContentWithTargetPathTemp" />
+    </AssignTargetPath>
+
+    <CreateItem
+      Include="@(ContentWithTargetPathTemp)"
+      AdditionalMetadata="TargetPath=$(ContentRootDirectoryDir)%(ContentWithTargetPathTemp.TargetPath)">
+      <Output TaskParameter="Include" ItemName="ContentWithTargetPath"/>
+    </CreateItem>
+
+    <AssignTargetPath Files="@(None)" RootFolder="$(MSBuildProjectDirectory)">
+      <Output TaskParameter="AssignedFiles" ItemName="_NoneWithTargetPathTemp" />
+    </AssignTargetPath>
+
+    <CreateItem
+      Include="@(_NoneWithTargetPathTemp)"
+      AdditionalMetadata="TargetPath=$(ContentRootDirectoryDir)%(_NoneWithTargetPathTemp.TargetPath)">
+      <Output TaskParameter="Include" ItemName="_NoneWithTargetPath"/>
+    </CreateItem>
+
+  </Target>
+
+  <!--
+    ============================================================
+                                        GetCopyToOutputDirectoryItems
+
+    Override the standard Microsoft.Common.targets' definition of
+    GetCopyToOutputDirectoryItems in order to add our built content
+    to @(AllItemsFullPathWithTargetPath).
+    ============================================================
+    -->
+  <PropertyGroup>
+    <GetCopyToOutputDirectoryItemsDependsOn>
+      GetBuiltContentWithTargetPaths;
+      GetBuiltXactContentWithTargetPaths;
+      AssignTargetPaths
+    </GetCopyToOutputDirectoryItemsDependsOn>
+  </PropertyGroup>
+
+  <Target
+      Name="GetCopyToOutputDirectoryItems"
+      Outputs="@(AllItemsFullPathWithTargetPath)"
+      DependsOnTargets="$(GetCopyToOutputDirectoryItemsDependsOn)">
+
+    <!-- Do not get items from child projects. Referenced projects are used by the Content Pipeline,
+         and we do not want to pass build-related assemblies to projects that reference this one. This
+         also means a Content project cannot reference another Content project. -->
+
+    <!-- Get built content items from this project. -->
+    <CreateItem
+        Include="@(BuiltContentWithTargetPaths->'%(FullPath)')"
+        Condition="'%(BuiltContentWithTargetPaths.CopyToOutputDirectory)'=='Always' or '%(BuiltContentWithTargetPaths.CopyToOutputDirectory)'=='PreserveNewest'"
+                >
+      <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
+      <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways"
+              Condition="'%(BuiltContentWithTargetPaths.CopyToOutputDirectory)'=='Always'"/>
+      <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory"
+              Condition="'%(BuiltContentWithTargetPaths.CopyToOutputDirectory)'=='PreserveNewest'"/>
+    </CreateItem>
+
+    <!-- Get built XACT content items from this project. -->
+    <CreateItem
+        Include="@(BuiltXactContentWithTargetPaths->'%(FullPath)')"
+        Condition="'%(BuiltXactContentWithTargetPaths.CopyToOutputDirectory)'=='Always' or '%(BuiltXactContentWithTargetPaths.CopyToOutputDirectory)'=='PreserveNewest'"
+                >
+      <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
+      <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways"
+              Condition="'%(BuiltXactContentWithTargetPaths.CopyToOutputDirectory)'=='Always'"/>
+      <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory"
+              Condition="'%(BuiltXactContentWithTargetPaths.CopyToOutputDirectory)'=='PreserveNewest'"/>
+    </CreateItem>
+
+    <!-- Get source items from this project. -->
+    <CreateItem
+        Include="@(ContentWithTargetPath->'%(FullPath)')"
+        Condition="'%(ContentWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(ContentWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"
+                >
+      <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
+      <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways"
+              Condition="'%(ContentWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
+      <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory"
+              Condition="'%(ContentWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
+    </CreateItem>
+
+    <!-- Content projects do not have Embedded Resource build actions. -->
+
+    <CreateItem
+        Include="@(Compile->'%(FullPath)')"
+        Condition="'%(Compile.CopyToOutputDirectory)'=='Always' or '%(Compile.CopyToOutputDirectory)'=='PreserveNewest'">
+      <Output TaskParameter="Include" ItemName="_CompileItemsToCopy"/>
+    </CreateItem>
+    <AssignTargetPath Files="@(_CompileItemsToCopy)" RootFolder="$(MSBuildProjectDirectory)">
+      <Output TaskParameter="AssignedFiles" ItemName="_CompileItemsToCopyWithTargetPathTemp" />
+    </AssignTargetPath>
+    <CreateItem
+      Include="@(_CompileItemsToCopyWithTargetPathTemp)"
+      AdditionalMetadata="TargetPath=$(ContentRootDirectoryDir)%(_CompileItemsToCopyWithTargetPathTemp.TargetPath)">
+      <Output TaskParameter="Include" ItemName="_CompileItemsToCopyWithTargetPath"/>
+    </CreateItem>
+    <CreateItem Include="@(_CompileItemsToCopyWithTargetPath)">
+      <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
+      <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways"
+              Condition="'%(_CompileItemsToCopyWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
+      <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory"
+              Condition="'%(_CompileItemsToCopyWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
+    </CreateItem>
+
+    <CreateItem
+        Include="@(_NoneWithTargetPath->'%(FullPath)')"
+        Condition="'%(_NoneWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(_NoneWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"
+                >
+      <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
+      <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways"
+              Condition="'%(_NoneWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
+      <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory"
+              Condition="'%(_NoneWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
+    </CreateItem>
+
+  </Target>
+
+  <!--
+    ============================================================
+                                        CopyFilesToOutputDirectory
+
+    Override the standard Microsoft.Common.targets CopyFilesToOutputDirectory, since our content
+    project type doesn't build most of the regular code build outputs. We also don't copy references
+    that were copy local into the output directory, since references are for use during build only,
+    not runtime. Finally, we leave it up to the parent project to copy any of our source items to
+    its own output directory.
+    ============================================================
+    -->
+  <Target Name="CopyFilesToOutputDirectory"/>
+  
+</Project>

+ 26 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.GameStudio.Windows.targets

@@ -0,0 +1,26 @@
+<!--
+***********************************************************************************************
+Microsoft.Xna.GameStudio.Windows.targets
+
+WARNING:  DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
+          created a backup copy.  Incorrect changes to this file will make it
+          impossible to load or build your projects from the command-line or the IDE.
+
+This file defines the steps in the standard build process specific for XNA Game Studio
+projects targeting the Windows platform.
+
+Copyright (C) Microsoft Corporation. All rights reserved.
+***********************************************************************************************
+-->
+
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <!-- AvailablePlatforms is the list of platform targets available. -->
+  <PropertyGroup>
+    <AvailablePlatforms>x86</AvailablePlatforms>
+  </PropertyGroup>
+
+  <Import Project="Microsoft.Xna.GameStudio.Common.targets" />
+  <Import Project="Microsoft.Xna.GameStudio.Content.targets" />
+
+</Project>

+ 54 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/FBX/XNA/XNA Game Studio/v4.0/Microsoft.Xna.GameStudio.Xbox 360.targets

@@ -0,0 +1,54 @@
+<!--
+***********************************************************************************************
+Microsoft.Xna.GameStudio.Xbox 360.targets
+
+WARNING:  DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
+          created a backup copy.  Incorrect changes to this file will make it
+          impossible to load or build your projects from the command-line or the IDE.
+
+This file defines the steps in the standard build process specific for XNA Game Studio
+projects targeting the Xbox 360 platform.
+
+Copyright (C) Microsoft Corporation. All rights reserved.
+***********************************************************************************************
+-->
+
+<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+  <!-- AvailablePlatforms is the list of platform targets available. -->
+  <PropertyGroup>
+    <AvailablePlatforms>Xbox 360</AvailablePlatforms>
+  </PropertyGroup>
+
+  <!--
+        These are used to have the AssemblySearchPaths include the following registry location
+        when resolving assemblies:
+              
+            HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\XNA\AssemblyFolders\$(XnaFrameworkVersion)\$(XnaPlatform)\AssemblyFoldersEx
+
+    -->
+  <PropertyGroup>
+    <FrameworkRegistryBase>SOFTWARE\Microsoft\XNA\AssemblyFolders</FrameworkRegistryBase>
+    <AssemblyFoldersSuffix>$(XnaPlatform)\AssemblyFoldersEx</AssemblyFoldersSuffix>
+  </PropertyGroup>
+
+  <!--
+    In MSBuild 3.5, the ResolveAssemblyReference takes a new, redundant input
+    parameter to define the TargetFrameworkDirectory. We want this path defined
+    only for Windows platforms, because it allows resolution against Windows-only
+    assemblies.
+  -->
+  <Target
+    Name="GetFrameworkPaths"
+    DependsOnTargets="$(GetFrameworkPathsDependsOn)"
+    >
+
+    <PropertyGroup>
+      <TargetFrameworkDirectory Condition=" '$(XnaPlatform)' == 'Xbox 360' ">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\XNA\Game Studio\v4.0@InstallPath)References\Xbox360\</TargetFrameworkDirectory>
+    </PropertyGroup>
+  </Target>
+
+  <Import Project="Microsoft.Xna.GameStudio.Common.targets" />
+  <Import Project="Microsoft.Xna.GameStudio.Content.targets" />
+
+</Project>

+ 13 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/IExporter.cs

@@ -0,0 +1,13 @@
+using System;
+
+namespace BabylonExport
+{
+    public interface IExporter
+    {
+        event Action<int> OnImportProgressChanged;
+
+        string SupportedExtensions { get; }
+
+        void GenerateBabylonFile(string file, string outputFile, bool skinned);
+    }
+}

+ 431 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/MXB/NovaExporter.Materials.cs

@@ -0,0 +1,431 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using BabylonExport;
+using SharpDX.Direct3D9;
+using Vertice.Core;
+using Vertice.Nova;
+using Vertice.Nova.Core;
+using Vertice.Nova.Materials;
+using System.Windows.Forms;
+
+namespace BabylonExport.Exporters
+{
+    partial class NovaExporter
+    {
+        void DumpMaterials(BabylonScene babylonScene)
+        {
+            var count = 0;
+            foreach (NovaMaterial material in materialsToExport)
+            {
+                var stdMaterial = material as NovaStandardMaterial;
+
+                if (stdMaterial != null)
+                {
+                    DumpStandardMaterial(stdMaterial, babylonScene);
+                    continue;
+                }
+
+                var perPixelShader = material as NovaPerPixelShader;
+
+                if (perPixelShader != null)
+                {
+                    DumpPerPixelShader(perPixelShader, babylonScene);
+                    continue;
+                }
+
+                var multiMaterial = material as NovaMultiMaterial;
+
+                if (multiMaterial != null)
+                {
+                    DumpMultiMaterial(multiMaterial, babylonScene);
+                }
+
+                ReportProgressChanged(75 + (count++ * 25) / materialsToExport.Count);
+            }
+        }
+
+        void AttachMirrorPlane(BabylonTexture babylonTexture, NovaObject novaObject)
+        {
+            // Mirror plane
+            int f1, f2, f3;
+
+            if (novaObject.Is32bits)
+            {
+                f1 = novaObject.Indices32[2];
+                f2 = novaObject.Indices32[1];
+                f3 = novaObject.Indices32[0];
+            }
+            else
+            {
+                f1 = novaObject.Indices[2];
+                f2 = novaObject.Indices[1];
+                f3 = novaObject.Indices[0];
+            }
+            Vector3 a = novaObject.PositionOnlyVertices[f1];
+            Vector3 b = novaObject.PositionOnlyVertices[f2];
+            Vector3 c = novaObject.PositionOnlyVertices[f3];
+
+            var mainPlane = new Plane(a, b, c);
+
+            Matrix matrix = Matrix.Invert(novaObject.WorldMatrix);
+            matrix = Matrix.Transpose(matrix);
+            Plane plane = Plane.Transform(mainPlane, matrix);
+
+            babylonTexture.mirrorPlane = new[] { plane.Normal.X, plane.Normal.Y, plane.Normal.Z, plane.D };
+        }
+
+        void DumpStandardMaterial(NovaStandardMaterial stdMaterial, BabylonScene babylonScene)
+        {
+            var babylonMaterial = new BabylonMaterial();
+            babylonScene.MaterialsList.Add(babylonMaterial);
+
+            babylonMaterial.name = stdMaterial.Name;
+            babylonMaterial.id = stdMaterial.ID.ToString();
+            babylonMaterial.alpha = stdMaterial.Alpha;
+            babylonMaterial.ambient = (stdMaterial.Ambient * (1.0f - stdMaterial.SelfIllumination)).ToArray();
+            babylonMaterial.diffuse = (stdMaterial.Diffuse * (1.0f - stdMaterial.SelfIllumination)).ToArray();
+            babylonMaterial.emissive = (stdMaterial.Emissive * stdMaterial.SelfIllumination).ToArray();
+            babylonMaterial.specular = stdMaterial.Specular.ToArray();
+            babylonMaterial.specularPower = stdMaterial.SpecularSharpness;
+            babylonMaterial.backFaceCulling = (stdMaterial.CullMode == NovaCull.CounterClockwise);
+
+            if (stdMaterial.DiffuseTexture != null && stdMaterial.DiffuseTexture.HasTextureData && !stdMaterial.DiffuseTexture.IsVideo && !stdMaterial.DiffuseTexture.IsCubeRender)
+            {
+                babylonMaterial.diffuseTexture = new BabylonTexture();
+                DumpTexture(stdMaterial.DiffuseTexture, babylonMaterial.diffuseTexture, babylonScene);
+            }
+
+            if (stdMaterial.AmbientTexture != null && stdMaterial.AmbientTexture.HasTextureData && !stdMaterial.AmbientTexture.IsVideo && !stdMaterial.AmbientTexture.IsCubeRender)
+            {
+                babylonMaterial.ambientTexture = new BabylonTexture();
+                DumpTexture(stdMaterial.AmbientTexture, babylonMaterial.ambientTexture, babylonScene);
+            }
+
+            if (stdMaterial.OpacityTexture != null && stdMaterial.OpacityTexture.HasTextureData && !stdMaterial.OpacityTexture.IsVideo && !stdMaterial.OpacityTexture.IsCubeRender)
+            {
+                babylonMaterial.opacityTexture = new BabylonTexture();
+                DumpTexture(stdMaterial.OpacityTexture, babylonMaterial.opacityTexture, babylonScene);
+            }
+
+            if (mirrorsMaterials.ContainsKey(stdMaterial))
+            {
+                babylonMaterial.reflectionTexture = new BabylonTexture();
+                var novaObject = mirrorsMaterials[stdMaterial];
+                DumpRenderTargetTexture(stdMaterial.ReflectionTexture, babylonMaterial.reflectionTexture, novaObject.MirrorMapSize, novaObject.MirrorLevel, novaObject.MirroredObjects);
+
+                AttachMirrorPlane(babylonMaterial.reflectionTexture, novaObject);
+            }
+            else if (stdMaterial.ReflectionTexture != null && stdMaterial.ReflectionTexture.HasTextureData && !stdMaterial.ReflectionTexture.IsVideo && !stdMaterial.ReflectionTexture.IsCubeRender)
+            {
+                babylonMaterial.reflectionTexture = new BabylonTexture();
+                DumpTexture(stdMaterial.ReflectionTexture, babylonMaterial.reflectionTexture, babylonScene);
+            }
+
+            if (stdMaterial.EmissiveTexture != null && stdMaterial.EmissiveTexture.HasTextureData && !stdMaterial.EmissiveTexture.IsVideo && !stdMaterial.EmissiveTexture.IsCubeRender)
+            {
+                babylonMaterial.emissiveTexture = new BabylonTexture();
+                DumpTexture(stdMaterial.EmissiveTexture, babylonMaterial.emissiveTexture, babylonScene);
+            }
+
+            if (stdMaterial.SpecularTexture != null && stdMaterial.SpecularTexture.HasTextureData && !stdMaterial.SpecularTexture.IsVideo && !stdMaterial.SpecularTexture.IsCubeRender)
+            {
+                babylonMaterial.specularTexture = new BabylonTexture();
+                DumpTexture(stdMaterial.SpecularTexture, babylonMaterial.specularTexture, babylonScene);
+            }
+
+            if (stdMaterial.BumpTexture != null && stdMaterial.BumpTexture.HasTextureData && !stdMaterial.BumpTexture.IsVideo && !stdMaterial.BumpTexture.IsCubeRender)
+            {
+                babylonMaterial.bumpTexture = new BabylonTexture();
+                DumpTexture(stdMaterial.BumpTexture, babylonMaterial.bumpTexture, babylonScene);
+                babylonMaterial.bumpTexture.level /= 2.0f;
+            }
+        }
+
+        void DumpPerPixelShader(NovaPerPixelShader ppShader, BabylonScene babylonScene)
+        {
+            var babylonMaterial = new BabylonMaterial();
+            babylonScene.MaterialsList.Add(babylonMaterial);
+
+            babylonMaterial.name = ppShader.Name;
+            babylonMaterial.id = ppShader.ID.ToString();
+            babylonMaterial.alpha = ppShader.Alpha;
+            babylonMaterial.ambient = (ppShader.Ambient * (1.0f - ppShader.SelfIllumination)).ToArray();
+            babylonMaterial.diffuse = (ppShader.Diffuse * (1.0f - ppShader.SelfIllumination)).ToArray();
+            babylonMaterial.emissive = (ppShader.Emissive * ppShader.SelfIllumination).ToArray();
+            babylonMaterial.specular = ppShader.Specular.ToArray();
+            babylonMaterial.specularPower = ppShader.SpecularSharpness;
+            babylonMaterial.backFaceCulling = (ppShader.CullMode == NovaCull.CounterClockwise);
+
+            if (ppShader.DiffuseTexture != null && ppShader.DiffuseTexture.HasTextureData && !ppShader.DiffuseTexture.IsVideo && !ppShader.DiffuseTexture.IsCubeRender)
+            {
+                babylonMaterial.diffuseTexture = new BabylonTexture();
+                DumpTexture(ppShader.DiffuseTexture, babylonMaterial.diffuseTexture, babylonScene);
+            }
+
+            if (ppShader.AmbientTexture != null && ppShader.AmbientTexture.HasTextureData && !ppShader.AmbientTexture.IsVideo && !ppShader.AmbientTexture.IsCubeRender)
+            {
+                babylonMaterial.ambientTexture = new BabylonTexture();
+                DumpTexture(ppShader.AmbientTexture, babylonMaterial.ambientTexture, babylonScene);
+            }
+
+            if (ppShader.OpacityTexture != null && ppShader.OpacityTexture.HasTextureData && !ppShader.OpacityTexture.IsVideo && !ppShader.OpacityTexture.IsCubeRender)
+            {
+                babylonMaterial.opacityTexture = new BabylonTexture();
+                DumpTexture(ppShader.OpacityTexture, babylonMaterial.opacityTexture, babylonScene);
+            }
+
+            if (mirrorsMaterials.ContainsKey(ppShader))
+            {
+                babylonMaterial.reflectionTexture = new BabylonTexture();
+                var novaObject = mirrorsMaterials[ppShader];
+                DumpRenderTargetTexture(ppShader.ReflectionTexture, babylonMaterial.reflectionTexture, novaObject.MirrorMapSize, novaObject.MirrorLevel, novaObject.MirroredObjects);
+
+                AttachMirrorPlane(babylonMaterial.reflectionTexture, novaObject);
+            }
+            else if (ppShader.ReflectionTexture != null && ppShader.ReflectionTexture.HasTextureData && !ppShader.ReflectionTexture.IsVideo && !ppShader.ReflectionTexture.IsCubeRender)
+            {
+                babylonMaterial.reflectionTexture = new BabylonTexture();
+                DumpTexture(ppShader.ReflectionTexture, babylonMaterial.reflectionTexture, babylonScene);
+            }
+
+            // Refraction
+            if (ppShader.RefractionLevel > 0)
+            {
+                babylonMaterial.alpha = 1.0f - ppShader.RefractionLevel;
+            }
+
+            if (ppShader.EmissiveTexture != null && ppShader.EmissiveTexture.HasTextureData && !ppShader.EmissiveTexture.IsVideo && !ppShader.EmissiveTexture.IsCubeRender)
+            {
+                babylonMaterial.emissiveTexture = new BabylonTexture();
+                DumpTexture(ppShader.EmissiveTexture, babylonMaterial.emissiveTexture, babylonScene);
+            }
+
+            if (ppShader.SpecularTexture != null && ppShader.SpecularTexture.HasTextureData && !ppShader.SpecularTexture.IsVideo && !ppShader.SpecularTexture.IsCubeRender)
+            {
+                babylonMaterial.specularTexture = new BabylonTexture();
+                DumpTexture(ppShader.SpecularTexture, babylonMaterial.specularTexture, babylonScene);
+            }
+
+            if (ppShader.BumpTexture != null && ppShader.BumpTexture.HasTextureData && !ppShader.BumpTexture.IsVideo && !ppShader.BumpTexture.IsCubeRender)
+            {
+                babylonMaterial.bumpTexture = new BabylonTexture();
+                DumpTexture(ppShader.BumpTexture, babylonMaterial.bumpTexture, babylonScene);
+                babylonMaterial.bumpTexture.level /= 2.0f;
+            }
+        }
+
+        static void DumpMultiMaterial(NovaMultiMaterial multiMaterial, BabylonScene babylonScene)
+        {
+            var babylonMultiMaterial = new BabylonMultiMaterial();
+            babylonScene.MultiMaterialsList.Add(babylonMultiMaterial);
+
+            babylonMultiMaterial.name = multiMaterial.Name;
+            babylonMultiMaterial.id = multiMaterial.ID.ToString();
+
+            babylonMultiMaterial.materials = multiMaterial.Materials.Select(material => (material != null ? material.ID.ToString() : "")).ToArray();
+        }
+
+        void DumpTextureAnimation(NovaTexture texture, BabylonTexture babylonTexture)
+        {
+            var animations = new List<BabylonAnimation>();
+
+            DumpInterpolator("Texture UOffset", "uOffset", texture.UOffsetInterpolator, texture.ParentScene, animations);
+            DumpInterpolator("Texture VOffset", "vOffset", texture.VOffsetInterpolator, texture.ParentScene, animations);
+            DumpInterpolator("Texture UScale", "uScale", texture.UScaleInterpolator, texture.ParentScene, animations);
+            DumpInterpolator("Texture VScale", "vScale", texture.VScaleInterpolator, texture.ParentScene, animations);
+
+            babylonTexture.animations = animations.ToArray();
+        }
+
+        private void DumpCubeTexture(NovaTexture texture, BabylonTexture babylonTexture, BabylonScene babylonScene)
+        {
+            var textureFilename = Path.Combine(texture.LoadedTexture.Directory, texture.LoadedTexture.Filename);
+            var baseName = Path.GetFileNameWithoutExtension(texture.LoadedTexture.Filename);
+
+            babylonTexture.isCube = true;
+            babylonTexture.name = baseName;
+
+            baseName = Path.Combine(babylonScene.OutputPath, baseName);
+
+            if (!File.Exists(textureFilename))
+            {
+                texture.LoadedTexture.SaveToDDS(false, textureFilename);
+            }
+
+            if (!alreadyExportedTextures.Contains(textureFilename))
+            {
+                alreadyExportedTextures.Add(textureFilename);
+
+                // Use SharpDX to extract face images
+                var form = new Form { ClientSize = new Size(64, 64) };
+                var device = new Device(new Direct3D(), 0, DeviceType.Hardware, form.Handle,
+                                        CreateFlags.HardwareVertexProcessing,
+                                        new PresentParameters(form.ClientSize.Width, form.ClientSize.Height));
+
+                var cubeTexture = CubeTexture.FromFile(device, textureFilename);
+
+                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.PositiveX, 0))
+                {
+                    Surface.ToFile(surface, baseName + "_px.jpg", ImageFileFormat.Jpg);
+                }
+                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.PositiveY, 0))
+                {
+                    Surface.ToFile(surface, baseName + "_py.jpg", ImageFileFormat.Jpg);
+                }
+                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.PositiveZ, 0))
+                {
+                    Surface.ToFile(surface, baseName + "_pz.jpg", ImageFileFormat.Jpg);
+                }
+                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.NegativeX, 0))
+                {
+                    Surface.ToFile(surface, baseName + "_nx.jpg", ImageFileFormat.Jpg);
+                }
+                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.NegativeY, 0))
+                {
+                    Surface.ToFile(surface, baseName + "_ny.jpg", ImageFileFormat.Jpg);
+                }
+                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.NegativeZ, 0))
+                {
+                    Surface.ToFile(surface, baseName + "_nz.jpg", ImageFileFormat.Jpg);
+                }
+
+                cubeTexture.Dispose();
+                device.Dispose();
+                form.Dispose();
+            }
+        }
+
+        private void DumpRenderTargetTexture(NovaTexture texture, BabylonTexture babylonTexture, int renderSize, float level, NovaMirroredObjectsList renderList)
+        {
+            babylonTexture.level = level;
+            babylonTexture.hasAlpha = false;
+            babylonTexture.coordinatesMode = (int)NovaTexture.NovaTextureMapType.Projection;
+
+            babylonTexture.name = texture.Name;
+            babylonTexture.uOffset = texture.UOffset;
+            babylonTexture.vOffset = texture.VOffset;
+            babylonTexture.uScale = texture.UScale;
+            babylonTexture.vScale = texture.VScale;
+            babylonTexture.uAng = texture.UAng;
+            babylonTexture.vAng = texture.VAng;
+            babylonTexture.wAng = texture.WAng;
+            switch (texture.UAddressMode)
+            {
+                case NovaTextureAddress.Wrap:
+                    babylonTexture.wrapU = 1;
+                    break;
+                case NovaTextureAddress.Mirror:
+                    babylonTexture.wrapU = 2;
+                    break;
+                case NovaTextureAddress.Clamp:
+                    babylonTexture.wrapU = 0;
+                    break;
+            }
+            switch (texture.VAddressMode)
+            {
+                case NovaTextureAddress.Wrap:
+                    babylonTexture.wrapV = 1;
+                    break;
+                case NovaTextureAddress.Mirror:
+                    babylonTexture.wrapV = 2;
+                    break;
+                case NovaTextureAddress.Clamp:
+                    babylonTexture.wrapV = 0;
+                    break;
+            }
+            babylonTexture.coordinatesIndex = texture.MapCoordinateIndex;
+
+            DumpTextureAnimation(texture, babylonTexture);
+
+            babylonTexture.isRenderTarget = true;
+            babylonTexture.renderTargetSize = renderSize;
+
+            babylonTexture.renderList = renderList.Select(o => o.ID.ToString()).ToArray();
+        }
+
+        void DumpTexture(NovaTexture texture, BabylonTexture babylonTexture, BabylonScene babylonScene)
+        {
+            babylonTexture.level = texture.Level;
+            babylonTexture.hasAlpha = texture.HasAlpha;
+            babylonTexture.coordinatesMode = (int)texture.MapType;
+
+            if (texture.LoadedTexture.IsCube)
+            {
+                DumpCubeTexture(texture, babylonTexture, babylonScene);
+                return;
+            }
+
+            babylonTexture.name = texture.Name;
+            babylonTexture.uOffset = texture.UOffset;
+            babylonTexture.vOffset = texture.VOffset;
+            babylonTexture.uScale = texture.UScale;
+            babylonTexture.vScale = texture.VScale;
+            babylonTexture.uAng = texture.UAng;
+            babylonTexture.vAng = texture.VAng;
+            babylonTexture.wAng = texture.WAng;
+            switch (texture.UAddressMode)
+            {
+                case NovaTextureAddress.Wrap:
+                    babylonTexture.wrapU = 1;
+                    break;
+                case NovaTextureAddress.Mirror:
+                    babylonTexture.wrapU = 2;
+                    break;
+                case NovaTextureAddress.Clamp:
+                    babylonTexture.wrapU = 0;
+                    break;
+            }
+            switch (texture.VAddressMode)
+            {
+                case NovaTextureAddress.Wrap:
+                    babylonTexture.wrapV = 1;
+                    break;
+                case NovaTextureAddress.Mirror:
+                    babylonTexture.wrapV = 2;
+                    break;
+                case NovaTextureAddress.Clamp:
+                    babylonTexture.wrapV = 0;
+                    break;
+            }
+            babylonTexture.coordinatesIndex = texture.MapCoordinateIndex;
+
+            DumpTextureAnimation(texture, babylonTexture);
+
+            babylonTexture.name = CopyTexture(texture, babylonScene);
+        }
+
+        string CopyTexture(NovaTexture texture, BabylonScene babylonScene)
+        {
+            string name = texture.Name;
+            // Data
+            if (!alreadyExportedTextures.Contains(texture.Name))
+            {
+                alreadyExportedTextures.Add(texture.Name);
+
+                if (Path.GetExtension(texture.Name).ToLower() == ".dds" || Path.GetExtension(texture.Name).ToLower() == ".bmp")
+                {
+                    name = Path.GetFileNameWithoutExtension(texture.Name) + ".png";
+                    texture.LoadedTexture.SaveToPNG(Path.Combine(babylonScene.OutputPath, name));
+                }
+                else
+                {
+                    var sourceFile = Path.Combine(texture.Directory, texture.Filename);
+                    File.Copy(sourceFile, Path.Combine(babylonScene.OutputPath, Path.GetFileName(sourceFile)), true);
+                }
+            }
+            else
+            {
+                if (Path.GetExtension(texture.Name).ToLower() == ".dds" ||
+                    Path.GetExtension(texture.Name).ToLower() == ".bmp")
+                {
+                    name = Path.GetFileNameWithoutExtension(texture.Name) + ".png";
+                }
+            }
+
+            return name;
+        }
+    }
+}

+ 630 - 0
Exporters/FBX - OBJ/BabylonExport/Exporters/MXB/NovaExporter.cs

@@ -0,0 +1,630 @@
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.Serialization.Json;
+using Vertice.Core;
+using Vertice.Nova;
+using Vertice.Nova.Core;
+using Vertice.Nova.Core.DirectX9;
+using Vertice.Nova.Materials;
+using Vertice.Nova.Animations;
+using Vertice.Nova.Core.DirectX10;
+
+namespace BabylonExport.Exporters
+{
+    public partial class NovaExporter : IExporter
+    {
+        readonly List<string> alreadyExportedTextures = new List<string>();
+        readonly List<NovaMaterial> materialsToExport = new List<NovaMaterial>();
+        readonly List<NovaParticleSystem> particleSystemsToExport = new List<NovaParticleSystem>();
+        readonly Dictionary<NovaMaterial, NovaObject> mirrorsMaterials = new Dictionary<NovaMaterial, NovaObject>();
+
+        public event Action<int> OnImportProgressChanged;
+
+        public string SupportedExtensions
+        {
+            get
+            {
+                return ".mxb .mxc";
+            }
+        }
+
+        void ReportProgressChanged(int progress)
+        {
+            if (OnImportProgressChanged != null)
+            {
+                OnImportProgressChanged(progress);
+            }
+        }
+
+        public void GenerateBabylonFile(string file, string outputFile, bool skinned)
+        {
+            try
+            {
+                ReportProgressChanged(0);
+                NovaEngine.Launch<DirectX9Provider>("", 128, 128);
+                NovaScene novaScene = NovaEngine.CreateScene("TempScene");
+
+                if (file.EndsWith(".mxc"))
+                {
+                    NovaEngine.ResourceManager.ArchivePath = Path.GetFullPath(file);
+
+                    // Get the mbx file name
+                    file = NovaEngine.ResourceManager.GetStartSceneFilename();
+                }
+
+                novaScene.Load(file);
+                novaScene.Render(false);
+
+                Generate(novaScene, outputFile);
+            }
+
+            finally
+            {
+                NovaEngine.Stop();
+            }
+        }
+
+        void Generate(NovaScene scene, string outputFile)
+        {
+            ReportProgressChanged(25);
+            var babylonScene = new BabylonScene(Path.GetDirectoryName(outputFile));
+            alreadyExportedTextures.Clear();
+
+            babylonScene.autoClear = scene.AutoClear;
+            babylonScene.clearColor = scene.ClearColor.ToArray();
+            babylonScene.ambientColor = scene.AmbientColor.ToArray();
+            babylonScene.gravity = ((scene.Gravity == Vector3.Zero) ? new Vector3(0, -9.0f, 0) : scene.Gravity).ToArray();
+
+            // Fog
+            babylonScene.fogMode = (int)scene.FogMode;
+            babylonScene.fogColor = scene.FogColor.ToArray();
+            babylonScene.fogStart = scene.ActiveCamera.NearClip;
+            babylonScene.fogEnd = scene.ActiveCamera.FarClip;
+            babylonScene.fogDensity = scene.FogDensity;
+
+            // Cameras
+            DumpCameras(scene, babylonScene);
+
+            // Lights
+            DumpLights(scene, babylonScene);
+            ReportProgressChanged(50);
+
+            // Objects
+            DumpObjects(scene, babylonScene);
+
+            // Materials
+            DumpMaterials(babylonScene);
+
+            // Particles
+            DumpParticles(babylonScene);
+
+            // Output
+            babylonScene.Prepare(false);
+            using (var outputStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write))
+            {
+                var ser = new DataContractJsonSerializer(typeof(BabylonScene));
+                ser.WriteObject(outputStream, babylonScene);
+            }
+            ReportProgressChanged(100);
+        }
+
+        private void DumpParticles(BabylonScene babylonScene)
+        {
+            if (particleSystemsToExport.Count == 0)
+                return;
+
+            babylonScene.particleSystems = new BabylonParticleSystem[particleSystemsToExport.Count];
+
+            var index = 0;
+            foreach (var particleSystem in particleSystemsToExport)
+            {
+                babylonScene.particleSystems[index] = new BabylonParticleSystem
+                    {
+                        capacity = particleSystem.BufferSize,
+                        emitterId = particleSystem.Emitter.ID.ToString(),
+                        gravity = particleSystem.Gravity.ToArray(),
+                        direction1 = Vector3.TransformNormal(particleSystem.Direction1, particleSystem.Emitter.LocalMatrix).ToArray(),
+                        direction2 = Vector3.TransformNormal(particleSystem.Direction2, particleSystem.Emitter.LocalMatrix).ToArray(),
+                        minEmitBox = particleSystem.MinEmitBox.ToArray(),
+                        maxEmitBox = particleSystem.MaxEmitBox.ToArray(),
+                        color1 = particleSystem.Color1.ToArray(),
+                        color2 = particleSystem.Color2.ToArray(),
+                        colorDead = new RGBAColor(particleSystem.ColorDead.Red, particleSystem.ColorDead.Green, particleSystem.ColorDead.Blue, particleSystem.DeadAlpha).ToArray(),
+                        emitRate = particleSystem.EmitRate,
+                        updateSpeed = particleSystem.UpdateSpeed,
+                        targetStopFrame = particleSystem.TargetStopFrame,
+                        minEmitPower = particleSystem.MinEmitPower,
+                        maxEmitPower = particleSystem.MaxEmitPower,
+                        minLifeTime = particleSystem.MinLifeTime,
+                        maxLifeTime = particleSystem.MaxLifeTime,
+                        minSize = particleSystem.MinSize,
+                        maxSize = particleSystem.MaxSize,
+                        minAngularSpeed = particleSystem.MinAngularSpeed,
+                        maxAngularSpeed = particleSystem.MaxAngularSpeed,
+                        textureName = CopyTexture(particleSystem.Texture, babylonScene),
+                        blendMode = (int)particleSystem.BlendType,
+                        linkToEmitter = particleSystem.LinkToEmitter
+                    };
+
+                Vector4 textureMask = Vector4.Zero;
+
+                switch (particleSystem.TextureUsage)
+                {
+                    case NovaParticleSystem.ParticleTextureUsages.Alpha:
+                        textureMask = new Vector4(0, 0, 0, 1);
+                        break;
+                    case NovaParticleSystem.ParticleTextureUsages.RGB:
+                        textureMask = new Vector4(1, 1, 1, 0);
+                        break;
+                    case NovaParticleSystem.ParticleTextureUsages.ARGB:
+                        textureMask = new Vector4(1, 1, 1, 1);
+                        break;
+                }
+
+                babylonScene.particleSystems[index].textureMask = textureMask.ToArray();
+
+                index++;
+            }
+        }
+
+        bool IsInterpolatorIsEmpty(NovaFloatInterpolator interpolator)
+        {
+            for (int index = 0; index < interpolator.Datas.Length - 1; index++)
+            {
+                if (interpolator.Datas[index].Value != interpolator.Datas[index + 1].Value)
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        bool IsInterpolatorIsEmpty(NovaVector3Interpolator interpolator)
+        {
+            for (int index = 0; index < interpolator.Datas.Length - 1; index++)
+            {
+                if (interpolator.Datas[index].Value != interpolator.Datas[index + 1].Value)
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        bool DumpInterpolator(string name, string property, NovaFloatInterpolator interpolator, NovaScene scene, List<BabylonAnimation> animations, float mult = 1.0f)
+        {
+            if (interpolator.Ready && !IsInterpolatorIsEmpty(interpolator))
+            {
+                var fps = scene.AnimationFramerate < 1 ? 30 : scene.AnimationFramerate;
+                var babylonAnimation = new BabylonAnimation { name = name, property = property, dataType = BabylonAnimation.DataType.Float, framePerSecond = fps };
+
+                babylonAnimation.keys = interpolator.Datas.Select(value => new BabylonAnimationKey { frame = value.Key / scene.AnimationKeyStep, values = new[] { value.Value * mult } }).ToArray();
+
+                babylonAnimation.loopBehavior = interpolator.LoopAfter;
+
+                animations.Add(babylonAnimation);
+                return true;
+            }
+
+            return false;
+        }
+
+        bool DumpInterpolator(string name, string property, NovaVector3Interpolator interpolator, NovaScene scene, List<BabylonAnimation> animations)
+        {
+            if (interpolator.Ready && !IsInterpolatorIsEmpty(interpolator))
+            {
+                var fps = scene.AnimationFramerate < 1 ? 30 : scene.AnimationFramerate;
+                var babylonAnimation = new BabylonAnimation { name = name, property = property, dataType = BabylonAnimation.DataType.Vector3, framePerSecond = fps };
+
+                babylonAnimation.keys = interpolator.Datas.Select(value => new BabylonAnimationKey { frame = value.Key / scene.AnimationKeyStep, values = value.Value.ToArray() }).ToArray();
+
+                babylonAnimation.loopBehavior = interpolator.LoopAfter;
+
+                animations.Add(babylonAnimation);
+                return true;
+            }
+
+            return false;
+        }
+
+        bool DumpInterpolator(string name, string property, NovaQuaternionInterpolator interpolator, NovaScene scene, List<BabylonAnimation> animations)
+        {
+            if (interpolator.Ready)
+            {
+                var fps = scene.AnimationFramerate < 1 ? 30 : scene.AnimationFramerate;
+                var babylonAnimation = new BabylonAnimation { name = name, property = property, dataType = BabylonAnimation.DataType.Quaternion, framePerSecond = fps };
+
+                babylonAnimation.keys = interpolator.Datas.Select(value => new BabylonAnimationKey { frame = value.Key / scene.AnimationKeyStep, values = value.Value.ToArray() }).ToArray();
+
+                babylonAnimation.loopBehavior = interpolator.LoopAfter;
+
+                animations.Add(babylonAnimation);
+                return true;
+            }
+
+            return false;
+        }
+
+        void DumpObjects(NovaScene scene, BabylonScene babylonScene)
+        {
+            int count = 0;
+            foreach (NovaObject novaObject in scene.Objects)
+            {
+                if (novaObject.Is32bits)
+                {
+                    if (novaObject.SubObjects.Count == 1)
+                    {
+                        var total = novaObject.VerticesCount;
+                        const int step = 32000;
+                        var stepsCount = (int)(Math.Floor((float)total / step) + 1);
+
+                        for (var index = 0; index < stepsCount; index++)
+                        {
+                            var start = index * step;
+                            var end = (index + 1) * step;
+                            DumpObject(novaObject, babylonScene, scene, start, end, string.Format("#{0}", index));
+                        }
+                    }
+                }
+                else
+                {
+                    DumpObject(novaObject, babylonScene, scene, 0, novaObject.VerticesCount);
+                }
+
+                ReportProgressChanged(50 + (count++ * 25) / scene.Objects.Count);
+            }
+        }
+
+        void DumpObject(NovaObject novaObject, BabylonScene babylonScene, NovaScene scene, int startIndex, int endIndex, string nameIndex = "")
+        {
+            var babylonMesh = new BabylonMesh();
+            babylonScene.MeshesList.Add(babylonMesh);
+
+            babylonMesh.name = novaObject.Name + nameIndex;
+            babylonMesh.id = novaObject.ID.ToString();
+            babylonMesh.materialId = novaObject.Material == null ? "" : novaObject.Material.ID.ToString();
+            babylonMesh.parentId = novaObject.ParentEntity == null ? "" : novaObject.ParentEntity.ID.ToString();
+            babylonMesh.isEnabled = novaObject.Enabled;
+            babylonMesh.isVisible = novaObject.Renderable;
+            babylonMesh.visibility = novaObject.Visibility;
+            babylonMesh.checkCollisions = novaObject.CheckCollisions;
+            babylonMesh.receiveShadows = novaObject.ReceiveShadows;
+
+            if (novaObject.Billboard)
+            {
+                babylonMesh.billboardMode |= (novaObject.BillboardX ? 1 : 0);
+                babylonMesh.billboardMode |= (novaObject.BillboardY ? 2 : 0);
+                babylonMesh.billboardMode |= (novaObject.BillboardZ ? 4 : 0);
+            }
+
+            if (novaObject.ParticleSystem != null)
+            {
+                particleSystemsToExport.Add(novaObject.ParticleSystem);
+            }
+
+            // Mirror
+            if (novaObject.IsMirror && novaObject.Material != null)
+            {
+                mirrorsMaterials.Add(novaObject.Material, novaObject);
+            }
+
+            // World
+            babylonMesh.position = novaObject.Position.ToArray();
+            babylonMesh.rotation = novaObject.Rotation.ToArray();
+            babylonMesh.localMatrix = (Matrix.Scaling(novaObject.Scaling) * novaObject.LocalMatrix).ToArray();
+
+            // Animations
+            var animations = new List<BabylonAnimation>();
+
+            DumpInterpolator("Visibility animation", "visibility", novaObject.VisibilityInterpolator, scene, animations);
+
+            // Position
+            if (!DumpInterpolator("Position animation", "position", novaObject.PositionInterpolator, scene, animations))
+            {
+                DumpInterpolator("PositionX animation", "position.x", novaObject.PositionXInterpolator, scene, animations);
+                DumpInterpolator("PositionY animation", "position.y", novaObject.PositionYInterpolator, scene, animations);
+                DumpInterpolator("PositionZ animation", "position.z", novaObject.PositionZInterpolator, scene, animations);
+            }
+
+            // Rotation
+            if (!DumpInterpolator("Rotation animation", "rotation", novaObject.RotationInterpolator, scene, animations))
+            {
+                DumpInterpolator("RotationX animation", "rotation.x", novaObject.RotationXInterpolator, scene,
+                    animations, -novaObject.Determinant);
+                DumpInterpolator("RotationY animation", "rotation.y", novaObject.RotationYInterpolator, scene,
+                    animations, -novaObject.Determinant);
+                DumpInterpolator("RotationZ animation", "rotation.z", novaObject.RotationZInterpolator, scene,
+                    animations, -novaObject.Determinant);
+            }
+            else
+            {
+                babylonMesh.localMatrix = Matrix.Identity.ToArray();
+                babylonMesh.scaling = novaObject.Scaling.ToArray();
+            }
+
+            // Scaling
+            if (!DumpInterpolator("Scaling animation", "scaling", novaObject.ScalingInterpolator, scene, animations))
+            {
+                DumpInterpolator("ScalingX animation", "scaling.x", novaObject.ScalingXInterpolator, scene, animations);
+                DumpInterpolator("ScalingY animation", "scaling.y", novaObject.ScalingYInterpolator, scene, animations);
+                DumpInterpolator("ScalingZ animation", "scaling.z", novaObject.ScalingZInterpolator, scene, animations);
+            }
+            else
+            {
+                babylonMesh.localMatrix = novaObject.LocalMatrix.ToArray();
+                babylonMesh.scaling = novaObject.Scaling.ToArray();
+            }
+
+            babylonMesh.animations = animations.ToArray();
+            babylonMesh.autoAnimate = novaObject.AutoAnimate;
+            
+            if (novaObject.AutoAnimate)
+            {
+                babylonMesh.autoAnimateFrom = novaObject.AnimationStartKey;
+                if (novaObject.AnimationEndKey == -1)
+                {
+                    babylonMesh.autoAnimateTo = scene.AnimationKeyMax / scene.AnimationKeyStep;
+                    babylonMesh.autoAnimateLoop = true;
+                }
+                else
+                {
+                    babylonMesh.autoAnimateTo = novaObject.AnimationEndKey;
+                }
+            }
+
+            // Vertices & faces
+            var exportedVerticesCount = DumpObjectGeometry(novaObject, babylonMesh, startIndex, endIndex);
+
+            // Subobjects
+            var subMeshes = new List<BabylonSubMesh>();
+
+            if (novaObject.Is32bits)
+            {
+                var subMesh = new BabylonSubMesh();
+                subMesh.materialIndex = 0;
+                subMesh.verticesStart = 0;
+                subMesh.verticesCount = exportedVerticesCount;
+                subMesh.indexStart = 0;
+                subMesh.indexCount = babylonMesh.indices.Length;
+
+                subMeshes.Add(subMesh);
+            }
+            else
+            {
+                foreach (NovaSubObject subObject in novaObject.SubObjects)
+                {
+                    var subMesh = new BabylonSubMesh();
+                    subMesh.materialIndex = subObject.AttributeRange.AttributeId;
+                    subMesh.verticesStart = subObject.AttributeRange.VertexStart;
+                    subMesh.verticesCount = subObject.AttributeRange.VertexCount;
+                    subMesh.indexStart = subObject.AttributeRange.FaceStart * 3;
+                    subMesh.indexCount = subObject.AttributeRange.FaceCount * 3;
+
+                    subMeshes.Add(subMesh);
+                }                
+            }
+            babylonMesh.subMeshes = subMeshes.ToArray();
+
+            if (novaObject.Material != null)
+            {
+                if (!materialsToExport.Contains(novaObject.Material))
+                {
+                    materialsToExport.Add(novaObject.Material);
+                    var multiMat = novaObject.Material as NovaMultiMaterial;
+
+                    if (multiMat != null)
+                    {
+                        foreach (var mat in multiMat.Materials)
+                        {
+                            if (!materialsToExport.Contains(mat))
+                            {
+                                materialsToExport.Add(mat);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        private void DumpVertex(NovaCustomVertexFormat.GlobalVector3 vertex, List<float> positions, List<float> normals, List<float> uvs, List<float> uvs2, List<float> colors, Matrix transformMatrix, NovaObject novaObject)
+        {
+            var position = Vector3.TransformCoordinate(vertex.Position, transformMatrix);
+            var normal = Vector3.TransformNormal(vertex.Normal, transformMatrix);
+
+            positions.Add(position.X); positions.Add(position.Y); positions.Add(position.Z);
+            normals.Add(normal.X); normals.Add(normal.Y); normals.Add(normal.Z);
+            uvs.Add(vertex.Tu); uvs.Add(vertex.Tv);
+
+            if (novaObject.Use2TextureCoordinatesForMeshCreation)
+            {
+                uvs2.Add(vertex.Tu2); uvs2.Add(vertex.Tv2);
+            }
+
+            if (novaObject.VertexPaint)
+            {
+                var color = RGBAColor.FromArgb((int) vertex.Color);
+                colors.Add(color.Red); colors.Add(color.Green); colors.Add(color.Blue);
+            }
+        }
+
+        private int DumpObjectGeometry(NovaObject novaObject, BabylonMesh babylonMesh, int startIndex, int endIndex)
+        {
+            var verticesIndices = new int[novaObject.VerticesCount];
+            for (var index = 0; index < verticesIndices.Length; index++)
+            {
+                verticesIndices[index] = -1;
+            }
+
+            // Vertices
+            var transformMatrix = Matrix.Identity;//.Scaling(novaObject.Scaling) * novaObject.LocalMatrix;
+            var indicesList = new List<int>();
+
+            NovaCustomVertexFormat.GlobalVector3[] vertices = novaObject.InternalMesh.LockVertexBuffer<NovaCustomVertexFormat.GlobalVector3>(NovaLock.ReadOnly, novaObject.VerticesCount);
+
+            // Faces
+            INovaDataStream data = novaObject.InternalMesh.LockIndexBuffer(NovaLock.ReadOnly);
+
+            int[] indices;
+
+            if (novaObject.Is32bits)
+            {
+                indices = data.Read<int>(novaObject.FacesCount * 3 * 4);
+            }
+            else
+            {
+                indices = (data.Read<ushort>(novaObject.FacesCount * 3 * 4)).Select(i => (int)i).ToArray();
+            }
+
+            var positions = new List<float>();
+            var normals = new List<float>();
+            var uvs = new List<float>();
+            var uvs2 = new List<float>();
+            var colors = new List<float>();
+            int exportedVerticesCount = 0;
+            for (var index = 0; index < novaObject.FacesCount; index++)
+            {
+                var v0 = indices[index * 3];
+                var v1 = indices[index * 3 + 1];
+                var v2 = indices[index * 3 + 2];
+
+                if (v0 < startIndex || v1 < startIndex || v2 < startIndex)
+                {
+                    continue;
+                }
+
+                if (v0 >= startIndex && v0 < endIndex || v1 >= startIndex && v1 < endIndex || v2 >= startIndex && v2 < endIndex)
+                {
+                    if (verticesIndices[v0] == -1)
+                    {
+                        verticesIndices[v0] = exportedVerticesCount++;
+                        DumpVertex(vertices[v0], positions, normals, uvs, uvs2, colors, transformMatrix, novaObject);
+                    }
+                    if (verticesIndices[v1] == -1)
+                    {
+                        verticesIndices[v1] = exportedVerticesCount++;
+                        DumpVertex(vertices[v1], positions, normals, uvs, uvs2, colors, transformMatrix, novaObject);
+                    }
+                    if (verticesIndices[v2] == -1)
+                    {
+                        verticesIndices[v2] = exportedVerticesCount++;
+                        DumpVertex(vertices[v2], positions, normals, uvs, uvs2, colors, transformMatrix, novaObject);
+                    }
+
+                    indicesList.Add(verticesIndices[v0]);
+                    indicesList.Add(verticesIndices[v1]);
+                    indicesList.Add(verticesIndices[v2]);
+                }
+            }
+
+            if (positions.Count > 0)
+            {
+                babylonMesh.positions = positions.ToArray();
+            }
+            if (normals.Count > 0)
+            {
+                babylonMesh.normals = normals.ToArray();
+            }
+            if (uvs.Count > 0)
+            {
+                babylonMesh.uvs = uvs.ToArray();
+            }
+            if (uvs2.Count > 0)
+            {
+                babylonMesh.uvs2 = uvs2.ToArray();
+            }
+            if (colors.Count > 0)
+            {
+                babylonMesh.colors = colors.ToArray();
+            }
+            babylonMesh.indices = indicesList.ToArray();
+
+            // Invert normal order
+            for (var index = 0; index < babylonMesh.indices.Length; index += 3)
+            {
+                var temp = babylonMesh.indices[index];
+                babylonMesh.indices[index] = babylonMesh.indices[index + 2];
+                babylonMesh.indices[index + 2] = temp;
+            }
+
+            novaObject.InternalMesh.UnlockIndexBuffer();
+            novaObject.InternalMesh.UnlockVertexBuffer();
+
+            return exportedVerticesCount;
+        }
+
+        static void DumpCameras(NovaScene scene, BabylonScene babylonScene)
+        {
+            foreach (NovaCamera camera in scene.Cameras)
+            {
+                var babylonCamera = new BabylonCamera();
+                babylonScene.CamerasList.Add(babylonCamera);
+
+                babylonCamera.name = camera.Name;
+                babylonCamera.id = camera.ID.ToString();
+                babylonCamera.position = camera.Position.ToArray();
+                babylonCamera.rotation = camera.Rotation.ToArray();
+                babylonCamera.fov = camera.FOV;
+                babylonCamera.minZ = camera.NearClip;
+                babylonCamera.maxZ = camera.FarClip;
+                babylonCamera.inertia = camera.Inertia;
+                babylonCamera.speed = camera.Speed;
+                babylonCamera.checkCollisions = camera.CheckCollisions;
+                babylonCamera.applyGravity = camera.ApplyGravity;
+                babylonCamera.ellipsoid = camera.EllipsoidVector.ToArray();
+            }
+
+            if (scene.ActiveCamera != null)
+            {
+                babylonScene.activeCameraID = scene.ActiveCamera.ID.ToString();
+            }
+        }
+
+        static void DumpLights(NovaScene scene, BabylonScene babylonScene)
+        {
+            foreach (NovaLight light in scene.Lights)
+            {
+                if (light.Enabled)
+                {
+                    var babylonLight = new BabylonLight();
+                    babylonScene.LightsList.Add(babylonLight);
+
+                    babylonLight.name = light.Name;
+                    babylonLight.id = light.ID.ToString();
+                    switch (light.Type)
+                    {
+                        case NovaLightType.Point:
+                            babylonLight.type = 0;
+                            babylonLight.position = light.Position.ToArray();
+                            break;
+                        case NovaLightType.Spot:
+                        case NovaLightType.Directional:
+                            babylonLight.type = 1;
+                            babylonLight.position = light.Position.ToArray();
+                            babylonLight.direction = light.Direction.ToArray();
+                            break;
+                    }
+                    babylonLight.diffuse = light.Diffuse.ToArray();
+                    babylonLight.specular = light.Specular.ToArray();
+                    babylonLight.intensity = light.Multiplicator;
+
+                    if (light.ShadowMembers.Count > 0)
+                    {
+                        var shadowGenerator = new BabylonShadowGenerator
+                        {
+                            useVarianceShadowMap = true,
+                            lightId = light.ID.ToString(),
+                            mapSize = light.ShadowMapSize,
+                            renderList = light.ShadowMembers.Select(m => m.ID.ToString()).ToArray()
+                        };
+                        babylonScene.ShadowGeneratorsList.Add(shadowGenerator);
+                    }
+                }
+            }
+        }
+
+    }
+}

+ 123 - 0
Exporters/FBX - OBJ/BabylonExport/Program.cs

@@ -0,0 +1,123 @@
+using System;
+using System.IO;
+using System.Reflection;
+using BabylonExport.Exporters;
+
+namespace BabylonExport
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            try
+            {
+                if (args.Length < 2)
+                {
+                    DisplayUsage();
+                    return;
+                }
+
+                // Parsing arguments
+                string input = "";
+                string output = "";
+                bool skinned = false;
+                foreach (var arg in args)
+                {
+                    var order = arg.Substring(0, 3);
+
+                    switch (order)
+                    {
+                        case "/i:":
+                            input = arg.Substring(3);
+                            break;
+                        case "/o:":
+                            output = arg.Substring(3);
+                            break;
+                        case "/sk":
+                            skinned = true;
+                            break;
+                        default:
+                            DisplayUsage();
+                            return;
+                    }
+                }
+
+                if (string.IsNullOrEmpty(input) || string.IsNullOrEmpty(output))
+                {
+                    DisplayUsage();
+                    return;
+                }
+                var extension = Path.GetExtension(input).ToLower();
+                var outputName = Path.Combine(output, Path.GetFileNameWithoutExtension(input) + ".babylon");
+                if (!Directory.Exists(output))
+                {
+                    Directory.CreateDirectory(output);
+                }
+
+                // Browsing exporters
+                foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
+                {
+                    var interf = type.GetInterface("BabylonExport.IExporter");
+                    if (interf != null)
+                    {
+                        var importer = (IExporter)Activator.CreateInstance(type);
+
+                        if (!importer.SupportedExtensions.Contains(extension))
+                        {
+                            continue;
+                        }
+
+                        Console.WriteLine("Using " + type);
+
+                        // Importation
+                        try
+                        {
+                            importer.OnImportProgressChanged += progress =>
+                                {
+                                    Console.CursorLeft = 0;
+                                    Console.Write("Generation....{0} %", progress);
+                                };
+
+                            Console.ForegroundColor = ConsoleColor.Green;
+                            Console.WriteLine("Generation of " + outputName + " started");
+                            Console.WriteLine();
+                            Console.ResetColor();
+                            importer.GenerateBabylonFile(input, outputName, skinned);
+                            Console.ForegroundColor = ConsoleColor.Green;
+                            Console.WriteLine();
+                            Console.WriteLine();
+                            Console.WriteLine("Generation of " + outputName + " successfull");
+                            Console.ResetColor();
+                        }
+                        catch (Exception ex)
+                        {
+                            Console.ForegroundColor = ConsoleColor.Red;
+                            Console.WriteLine();
+                            Console.WriteLine(ex.Message);
+                            Console.ResetColor();
+                        }
+                    }
+                }
+            }
+            catch (ReflectionTypeLoadException ex)
+            {
+                Console.ForegroundColor = ConsoleColor.Red;
+                Console.WriteLine("Fatal error encountered:");
+                Console.WriteLine(ex.LoaderExceptions[0].Message);
+                Console.ResetColor();
+            } 
+            catch (Exception ex)
+            {
+                Console.ForegroundColor = ConsoleColor.Red;
+                Console.WriteLine("Fatal error encountered:");
+                Console.WriteLine(ex.Message);
+                Console.ResetColor();
+            } 
+        }
+
+        static void DisplayUsage()
+        {
+            Console.WriteLine("Babylon Import usage: BabylonImport.exe /i:\"source file\" /o:\"output folder\" [/sk]");
+        }
+    }
+}

BIN
Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.AudioImporters.dll


BIN
Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.EffectImporter.dll


BIN
Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.FBXImporter.dll


BIN
Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.TextureImporter.dll


BIN
Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.VideoImporters.dll


BIN
Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.XImporter.dll


BIN
Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Content.Pipeline.dll


BIN
Exporters/FBX - OBJ/BabylonExport/Refs/Microsoft.Xna.Framework.Tools.Packaging.Tasks.dll


+ 0 - 0
Exporters/FBX - OBJ/BabylonExport/Refs/SharpDX.DXGI.dll


Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott