Explorar o código

Merge pull request #5 from BabylonJS/master

Pull from main repo
meulta %!s(int64=8) %!d(string=hai) anos
pai
achega
e545123aa1
Modificáronse 100 ficheiros con 14080 adicións e 10385 borrados
  1. 5 0
      .gitignore
  2. 48 48
      Exporters/3ds Max/BabylonExport.Entities/BabylonAbstractMesh.cs
  3. 39 39
      Exporters/3ds Max/BabylonExport.Entities/BabylonActions.cs
  4. 42 41
      Exporters/3ds Max/BabylonExport.Entities/BabylonAnimation.cs
  5. 14 14
      Exporters/3ds Max/BabylonExport.Entities/BabylonAnimationKey.cs
  6. 28 28
      Exporters/3ds Max/BabylonExport.Entities/BabylonBone.cs
  7. 84 84
      Exporters/3ds Max/BabylonExport.Entities/BabylonCamera.cs
  8. 84 78
      Exporters/3ds Max/BabylonExport.Entities/BabylonExport.Entities.csproj
  9. 27 27
      Exporters/3ds Max/BabylonExport.Entities/BabylonFresnelParameters.cs
  10. 19 19
      Exporters/3ds Max/BabylonExport.Entities/BabylonIAnimatable.cs
  11. 20 20
      Exporters/3ds Max/BabylonExport.Entities/BabylonLensFlare.cs
  12. 17 17
      Exporters/3ds Max/BabylonExport.Entities/BabylonLensFlareSystem.cs
  13. 76 76
      Exporters/3ds Max/BabylonExport.Entities/BabylonLight.cs
  14. 30 80
      Exporters/3ds Max/BabylonExport.Entities/BabylonMaterial.cs
  15. 131 122
      Exporters/3ds Max/BabylonExport.Entities/BabylonMesh.cs
  16. 17 17
      Exporters/3ds Max/BabylonExport.Entities/BabylonMultiMaterial.cs
  17. 172 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonPBRMaterial.cs
  18. 86 86
      Exporters/3ds Max/BabylonExport.Entities/BabylonParticleSystem.cs
  19. 24 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonProducer.cs
  20. 194 185
      Exporters/3ds Max/BabylonExport.Entities/BabylonScene.cs
  21. 39 36
      Exporters/3ds Max/BabylonExport.Entities/BabylonShadowGenerator.cs
  22. 20 17
      Exporters/3ds Max/BabylonExport.Entities/BabylonSkeleton.cs
  23. 86 86
      Exporters/3ds Max/BabylonExport.Entities/BabylonSound.cs
  24. 72 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonStandardMaterial.cs
  25. 24 24
      Exporters/3ds Max/BabylonExport.Entities/BabylonSubMesh.cs
  26. 87 87
      Exporters/3ds Max/BabylonExport.Entities/BabylonTexture.cs
  27. 36 36
      Exporters/3ds Max/BabylonExport.Entities/BabylonVector3.cs
  28. BIN=BIN
      Exporters/3ds Max/Max2Babylon-0.24.zip
  29. BIN=BIN
      Exporters/3ds Max/Max2Babylon-0.5.0.zip
  30. 277 0
      Exporters/3ds Max/Max2Babylon/2017/Max2Babylon2017.csproj
  31. 36 0
      Exporters/3ds Max/Max2Babylon/2017/Properties/AssemblyInfo.cs
  32. 63 0
      Exporters/3ds Max/Max2Babylon/2017/Properties/Resources.Designer.cs
  33. 120 0
      Exporters/3ds Max/Max2Babylon/2017/Properties/Resources.resx
  34. BIN=BIN
      Exporters/3ds Max/Max2Babylon/2017/Refs/Autodesk.Max.dll
  35. 8 8
      Exporters/3ds Max/Max2Babylon/BabylonActionCallback.cs
  36. 71 71
      Exporters/3ds Max/Max2Babylon/BabylonExportActionItem.cs
  37. 91 91
      Exporters/3ds Max/Max2Babylon/BabylonPropertiesActionItem.cs
  38. 52 52
      Exporters/3ds Max/Max2Babylon/Descriptor.cs
  39. 315 309
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Animation.cs
  40. 127 127
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Camera.cs
  41. 227 218
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Light.cs
  42. 149 149
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Material.cs
  43. 798 726
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs
  44. 70 65
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.ShadowGenerator.cs
  45. 135 134
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Skeleton.cs
  46. 249 244
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Texture.cs
  47. 351 322
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.cs
  48. 76 69
      Exporters/3ds Max/Max2Babylon/Exporter/GlobalVertex.cs
  49. 98 98
      Exporters/3ds Max/Max2Babylon/Forms/ActionsBuilderForm.Designer.cs
  50. 178 170
      Exporters/3ds Max/Max2Babylon/Forms/ActionsBuilderForm.cs
  51. 119 119
      Exporters/3ds Max/Max2Babylon/Forms/ActionsBuilderForm.resx
  52. 415 415
      Exporters/3ds Max/Max2Babylon/Forms/CameraPropertiesForm.Designer.cs
  53. 71 71
      Exporters/3ds Max/Max2Babylon/Forms/CameraPropertiesForm.cs
  54. 119 119
      Exporters/3ds Max/Max2Babylon/Forms/CameraPropertiesForm.resx
  55. 319 319
      Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.Designer.cs
  56. 229 229
      Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.cs
  57. 320 320
      Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.resx
  58. 419 405
      Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.Designer.cs
  59. 67 65
      Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.cs
  60. 119 119
      Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.resx
  61. 943 943
      Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.Designer.cs
  62. 127 122
      Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.cs
  63. 122 122
      Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.resx
  64. 286 272
      Exporters/3ds Max/Max2Babylon/Forms/ScenePropertiesForm.Designer.cs
  65. 49 47
      Exporters/3ds Max/Max2Babylon/Forms/ScenePropertiesForm.cs
  66. 122 122
      Exporters/3ds Max/Max2Babylon/Forms/ScenePropertiesForm.resx
  67. 152 152
      Exporters/3ds Max/Max2Babylon/Forms/Vector3Control.Designer.cs
  68. 30 30
      Exporters/3ds Max/Max2Babylon/Forms/Vector3Control.cs
  69. 119 119
      Exporters/3ds Max/Max2Babylon/Forms/Vector3Control.resx
  70. 128 128
      Exporters/3ds Max/Max2Babylon/GlobalUtility.cs
  71. 19 19
      Exporters/3ds Max/Max2Babylon/JsonTextWriterOptimized.cs
  72. 29 29
      Exporters/3ds Max/Max2Babylon/Loader.cs
  73. 834 834
      Exporters/3ds Max/Max2Babylon/Tools/Tools.cs
  74. 84 84
      Exporters/3ds Max/Max2Babylon/Tools/VNormal.cs
  75. 182 182
      Exporters/3ds Max/Max2Babylon/Tools/WebServer.cs
  76. 3 2
      Exporters/3ds Max/readme.md
  77. BIN=BIN
      Exporters/Blender/Blender2Babylon-5.0.zip
  78. 450 242
      Exporters/Blender/io_export_babylon.py
  79. 0 122
      Exporters/Blender/io_scene_map/__init__.py
  80. 0 508
      Exporters/Blender/io_scene_map/export_map.py
  81. 8 5
      Exporters/Blender/readme.md
  82. 89 0
      Exporters/Blender/src/__init__.py
  83. 174 0
      Exporters/Blender/src/animation.py
  84. 194 0
      Exporters/Blender/src/armature.py
  85. 216 0
      Exporters/Blender/src/camera.py
  86. 70 0
      Exporters/Blender/src/exporter_settings_panel.py
  87. 105 0
      Exporters/Blender/src/f_curve_animatable.py
  88. 297 0
      Exporters/Blender/src/json_exporter.py
  89. 222 0
      Exporters/Blender/src/light_shadow.py
  90. 56 0
      Exporters/Blender/src/logger.py
  91. 577 0
      Exporters/Blender/src/material.py
  92. 850 0
      Exporters/Blender/src/mesh.py
  93. 266 0
      Exporters/Blender/src/package_level.py
  94. 23 0
      Exporters/Blender/src/sound.py
  95. 45 0
      Exporters/Blender/src/world.py
  96. 0 0
      Exporters/FBX/3rdParty/Fbx2017.0.1/include/fbxsdk.h
  97. 0 0
      Exporters/FBX/3rdParty/Fbx2017.0.1/include/fbxsdk/core/arch/fbxalloc.h
  98. 0 0
      Exporters/FBX/3rdParty/Fbx2017.0.1/include/fbxsdk/core/arch/fbxarch.h
  99. 0 0
      Exporters/FBX/3rdParty/Fbx2017.0.1/include/fbxsdk/core/arch/fbxdebug.h
  100. 0 0
      Exporters/FBX/3rdParty/Fbx2016.1/include/fbxsdk/core/arch/fbxnew.h

+ 5 - 0
.gitignore

@@ -44,6 +44,8 @@ ipch/
 *.ncb
 *.opensdf
 *.sdf
+*.VC.db
+*.VC.opendb
 
 # Visual Studio profiler
 *.psess
@@ -123,3 +125,6 @@ node_modules
 
 # for JetBrains IDE
 .idea
+
+# for VSCode
+.vscode

+ 48 - 48
Exporters/3ds Max/BabylonExport.Entities/BabylonAbstractMesh.cs

@@ -1,48 +1,48 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonAbstractMesh: BabylonIAnimatable
-    {
-        [DataMember]
-        public string name { get; set; }
-        
-        [DataMember]
-        public float[] position { get; set; }
-
-        [DataMember]
-        public float[] rotation { get; set; }
-
-        [DataMember]
-        public float[] scaling { get; set; }
-
-        [DataMember]
-        public float[] rotationQuaternion { get; set; }
-
-        [DataMember]
-        public BabylonActions actions { get; set; }
-
-        [DataMember]
-        public BabylonAnimation[] animations { 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; }
-
-        public BabylonAbstractMesh()
-        {
-            position = new[] { 0f, 0f, 0f };
-            rotation = new[] { 0f, 0f, 0f };
-            scaling = new[] { 1f, 1f, 1f };
-        }
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonAbstractMesh: BabylonIAnimatable
+    {
+        [DataMember]
+        public string name { get; set; }
+        
+        [DataMember]
+        public float[] position { get; set; }
+
+        [DataMember]
+        public float[] rotation { get; set; }
+
+        [DataMember]
+        public float[] scaling { get; set; }
+
+        [DataMember]
+        public float[] rotationQuaternion { get; set; }
+
+        [DataMember]
+        public BabylonActions actions { get; set; }
+
+        [DataMember]
+        public BabylonAnimation[] animations { 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; }
+
+        public BabylonAbstractMesh()
+        {
+            position = new[] { 0f, 0f, 0f };
+            rotation = new[] { 0f, 0f, 0f };
+            scaling = new[] { 1f, 1f, 1f };
+        }
+    }
+}

+ 39 - 39
Exporters/3ds Max/BabylonExport.Entities/BabylonActions.cs

@@ -1,39 +1,39 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonActionsProperties
-    {
-        [DataMember]
-        public string name { get; set; }
-
-        [DataMember]
-        public string value { get; set; }
-
-        [DataMember]
-        public string targetType { get; set; }
-    }
-
-    [DataContract]
-    public class BabylonActions
-    {
-        [DataMember]
-        public string name { get; set; }
-
-        [DataMember]
-        public int type { get; set; }
-
-        [DataMember]
-        public bool detached { get; set; }
-
-        [DataMember]
-        public BabylonActions[] children { get; set; }
-
-        [DataMember]
-        public BabylonActions[] combine { get; set; }
-
-        [DataMember]
-        public BabylonActionsProperties[] properties { get; set; }
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonActionsProperties
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public string value { get; set; }
+
+        [DataMember]
+        public string targetType { get; set; }
+    }
+
+    [DataContract]
+    public class BabylonActions
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public int type { get; set; }
+
+        [DataMember]
+        public bool detached { get; set; }
+
+        [DataMember]
+        public BabylonActions[] children { get; set; }
+
+        [DataMember]
+        public BabylonActions[] combine { get; set; }
+
+        [DataMember]
+        public BabylonActionsProperties[] properties { get; set; }
+    }
+}

+ 42 - 41
Exporters/3ds Max/BabylonExport.Entities/BabylonAnimation.cs

@@ -1,41 +1,42 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonAnimation
-    {
-        [DataMember]
-        public string name { get; set; }
-
-        [DataMember]
-        public string property { get; set; }
-
-        [DataMember]
-        public int dataType { get; set; }
-
-        [DataMember]
-        public int 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
-        }
-
-        public enum LoopBehavior
-        {
-            Relative = 0,
-            Cycle = 1,
-            Constant = 2
-        }
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonAnimation
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public string property { get; set; }
+
+        [DataMember]
+        public int dataType { get; set; }
+
+        [DataMember]
+        public int 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,
+            Color3 = 4,
+        }
+
+        public enum LoopBehavior
+        {
+            Relative = 0,
+            Cycle = 1,
+            Constant = 2
+        }
+    }
+}

+ 14 - 14
Exporters/3ds Max/BabylonExport.Entities/BabylonAnimationKey.cs

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

+ 28 - 28
Exporters/3ds Max/BabylonExport.Entities/BabylonBone.cs

@@ -1,28 +1,28 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [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; }
-
-        public BabylonBone()
-        {
-            parentBoneIndex = -1;
-        }
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [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; }
+
+        public BabylonBone()
+        {
+            parentBoneIndex = -1;
+        }
+    }
+}

+ 84 - 84
Exporters/3ds Max/BabylonExport.Entities/BabylonCamera.cs

@@ -1,84 +1,84 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonCamera : BabylonIAnimatable
-    {
-        [DataMember]
-        public string name { get; set; }
-
-        [DataMember]
-        public string id { get; set; }
-
-        [DataMember]
-        public string parentId { get; set; }
-
-        [DataMember]
-        public string lockedTargetId { get; set; }
-
-        [DataMember]
-        public string type { 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; }
-
-        [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 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;
-        }
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonCamera : BabylonIAnimatable
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public string id { get; set; }
+
+        [DataMember]
+        public string parentId { get; set; }
+
+        [DataMember]
+        public string lockedTargetId { get; set; }
+
+        [DataMember]
+        public string type { 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; }
+
+        [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 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;
+        }
+    }
+}

+ 84 - 78
Exporters/3ds Max/BabylonExport.Entities/BabylonExport.Entities.csproj

@@ -1,79 +1,85 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="12.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>{6150965A-658C-4263-89AD-4F980EB0675D}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>BabylonExport.Entities</RootNamespace>
-    <AssemblyName>BabylonExport.Entities</AssemblyName>
-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <SccProjectName>SAK</SccProjectName>
-    <SccLocalPath>SAK</SccLocalPath>
-    <SccAuxPath>SAK</SccAuxPath>
-    <SccProvider>SAK</SccProvider>
-    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <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' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Runtime.Serialization" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="BabylonActions.cs" />
-    <Compile Include="BabylonAnimation.cs" />
-    <Compile Include="BabylonAnimationKey.cs" />
-    <Compile Include="BabylonBone.cs" />
-    <Compile Include="BabylonCamera.cs" />
-    <Compile Include="BabylonFresnelParameters.cs" />
-    <Compile Include="BabylonIAnimatable.cs" />
-    <Compile Include="BabylonLensFlare.cs" />
-    <Compile Include="BabylonLensFlareSystem.cs" />
-    <Compile Include="BabylonLight.cs" />
-    <Compile Include="BabylonMaterial.cs" />
-    <Compile Include="BabylonAbstractMesh.cs" />
-    <Compile Include="BabylonMesh.cs" />
-    <Compile Include="BabylonMultiMaterial.cs" />
-    <Compile Include="BabylonParticleSystem.cs" />
-    <Compile Include="BabylonScene.cs" />
-    <Compile Include="BabylonShadowGenerator.cs" />
-    <Compile Include="BabylonSkeleton.cs" />
-    <Compile Include="BabylonSound.cs" />
-    <Compile Include="BabylonSubMesh.cs" />
-    <Compile Include="BabylonTexture.cs" />
-    <Compile Include="BabylonVector3.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.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>
-  -->
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.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>{6150965A-658C-4263-89AD-4F980EB0675D}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>BabylonExport.Entities</RootNamespace>
+    <AssemblyName>BabylonExport.Entities</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SccProjectName>SAK</SccProjectName>
+    <SccLocalPath>SAK</SccLocalPath>
+    <SccAuxPath>SAK</SccAuxPath>
+    <SccProvider>SAK</SccProvider>
+    <TargetFrameworkProfile>
+    </TargetFrameworkProfile>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Runtime.Serialization" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="BabylonActions.cs" />
+    <Compile Include="BabylonAnimation.cs" />
+    <Compile Include="BabylonAnimationKey.cs" />
+    <Compile Include="BabylonBone.cs" />
+    <Compile Include="BabylonCamera.cs" />
+    <Compile Include="BabylonFresnelParameters.cs" />
+    <Compile Include="BabylonIAnimatable.cs" />
+    <Compile Include="BabylonLensFlare.cs" />
+    <Compile Include="BabylonLensFlareSystem.cs" />
+    <Compile Include="BabylonLight.cs" />
+    <Compile Include="BabylonMaterial.cs" />
+    <Compile Include="BabylonPBRMaterial.cs" />
+    <Compile Include="BabylonStandardMaterial.cs" />
+    <Compile Include="BabylonAbstractMesh.cs" />
+    <Compile Include="BabylonMesh.cs" />
+    <Compile Include="BabylonMultiMaterial.cs" />
+    <Compile Include="BabylonParticleSystem.cs" />
+    <Compile Include="BabylonProducer.cs" />
+    <Compile Include="BabylonScene.cs" />
+    <Compile Include="BabylonShadowGenerator.cs" />
+    <Compile Include="BabylonSkeleton.cs" />
+    <Compile Include="BabylonSound.cs" />
+    <Compile Include="BabylonSubMesh.cs" />
+    <Compile Include="BabylonTexture.cs" />
+    <Compile Include="BabylonVector3.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.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>

+ 27 - 27
Exporters/3ds Max/BabylonExport.Entities/BabylonFresnelParameters.cs

@@ -1,27 +1,27 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.Serialization;
-using System.Text;
-
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonFresnelParameters
-    {
-        [DataMember]
-        public float[] leftColor { get; set; }
-
-        [DataMember]
-        public float[] rightColor { get; set; }
-
-        [DataMember]
-        public bool isEnabled { get; set; }
-
-        [DataMember]
-        public float bias { get; set; }
-
-        [DataMember]
-        public float power { get; set; }
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.Text;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonFresnelParameters
+    {
+        [DataMember]
+        public float[] leftColor { get; set; }
+
+        [DataMember]
+        public float[] rightColor { get; set; }
+
+        [DataMember]
+        public bool isEnabled { get; set; }
+
+        [DataMember]
+        public float bias { get; set; }
+
+        [DataMember]
+        public float power { get; set; }
+    }
+}

+ 19 - 19
Exporters/3ds Max/BabylonExport.Entities/BabylonIAnimatable.cs

@@ -1,19 +1,19 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace BabylonExport.Entities
-{
-    public interface BabylonIAnimatable
-    {
-        BabylonAnimation[] animations { get; set; }
-        bool autoAnimate { get; set; }
-
-        int autoAnimateFrom { get; set; }
-
-        int autoAnimateTo { get; set; }
-
-        bool autoAnimateLoop { get; set; }
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BabylonExport.Entities
+{
+    public interface BabylonIAnimatable
+    {
+        BabylonAnimation[] animations { get; set; }
+        bool autoAnimate { get; set; }
+
+        int autoAnimateFrom { get; set; }
+
+        int autoAnimateTo { get; set; }
+
+        bool autoAnimateLoop { get; set; }
+    }
+}

+ 20 - 20
Exporters/3ds Max/BabylonExport.Entities/BabylonLensFlare.cs

@@ -1,20 +1,20 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonLensFlare
-    {
-        [DataMember]
-        public float position { get; set; }
-
-        [DataMember]
-        public float size { get; set; }
-
-        [DataMember]
-        public float[] color { get; set; }
-
-        [DataMember]
-        public string textureName { get; set; }
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonLensFlare
+    {
+        [DataMember]
+        public float position { get; set; }
+
+        [DataMember]
+        public float size { get; set; }
+
+        [DataMember]
+        public float[] color { get; set; }
+
+        [DataMember]
+        public string textureName { get; set; }
+    }
+}

+ 17 - 17
Exporters/3ds Max/BabylonExport.Entities/BabylonLensFlareSystem.cs

@@ -1,17 +1,17 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonLensFlareSystem
-    {
-        [DataMember]
-        public string emitterId { get; set; }
-
-        [DataMember]
-        public int borderLimit { get; set; }
-
-        [DataMember]
-        public BabylonLensFlare[] flares { get; set; }
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonLensFlareSystem
+    {
+        [DataMember]
+        public string emitterId { get; set; }
+
+        [DataMember]
+        public int borderLimit { get; set; }
+
+        [DataMember]
+        public BabylonLensFlare[] flares { get; set; }
+    }
+}

+ 76 - 76
Exporters/3ds Max/BabylonExport.Entities/BabylonLight.cs

@@ -1,76 +1,76 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonLight : BabylonIAnimatable
-    {
-        [DataMember]
-        public string name { get; set; }
-
-        [DataMember]
-        public string id { get; set; }
-
-        [DataMember]
-        public string parentId { 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; }
-
-        [DataMember]
-        public float range { get; set; }
-
-        [DataMember]
-        public float exponent { get; set; }
-
-        [DataMember]
-        public float angle { get; set; }
-
-        [DataMember]
-        public float[] groundColor { get; set; }
-
-        [DataMember]
-        public string[] excludedMeshesIds { get; set; }
-
-        [DataMember]
-        public string[] includedOnlyMeshesIds { 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 BabylonLight()
-        {
-            diffuse = new[] {1.0f, 1.0f, 1.0f};
-            specular = new[] { 1.0f, 1.0f, 1.0f };
-            intensity = 1.0f;
-            range = float.MaxValue;
-        }
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonLight : BabylonIAnimatable
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public string id { get; set; }
+
+        [DataMember]
+        public string parentId { 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; }
+
+        [DataMember]
+        public float range { get; set; }
+
+        [DataMember]
+        public float exponent { get; set; }
+
+        [DataMember]
+        public float angle { get; set; }
+
+        [DataMember]
+        public float[] groundColor { get; set; }
+
+        [DataMember]
+        public string[] excludedMeshesIds { get; set; }
+
+        [DataMember]
+        public string[] includedOnlyMeshesIds { 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 BabylonLight()
+        {
+            diffuse = new[] {1.0f, 1.0f, 1.0f};
+            specular = new[] { 1.0f, 1.0f, 1.0f };
+            intensity = 1.0f;
+            range = float.MaxValue;
+        }
+    }
+}

+ 30 - 80
Exporters/3ds Max/BabylonExport.Entities/BabylonMaterial.cs

@@ -1,80 +1,30 @@
-using System.Runtime.Serialization;
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonMaterial
-    {
-        [DataMember]
-        public string name { get; set; }
-
-        [DataMember]
-        public string id { get; set; }
-
-        [DataMember]
-        public bool backFaceCulling { get; set; }
-
-        [DataMember]
-        public bool wireframe { 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 BabylonFresnelParameters diffuseFresnelParameters { get; set; }
-
-        [DataMember]
-        public BabylonTexture ambientTexture { get; set; }
-
-        [DataMember]
-        public BabylonTexture opacityTexture { get; set; }
-
-        [DataMember]
-        public BabylonFresnelParameters opacityFresnelParameters { get; set; }
-
-        [DataMember]
-        public BabylonTexture reflectionTexture { get; set; }
-
-        [DataMember]
-        public BabylonFresnelParameters reflectionFresnelParameters { get; set; }
-
-        [DataMember]
-        public BabylonTexture emissiveTexture { get; set; }
-        [DataMember]
-        public BabylonFresnelParameters emissiveFresnelParameters { 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;
-        }
-    }
-}
+using System.Runtime.Serialization;
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonMaterial
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public string id { get; set; }
+
+        [DataMember]
+        public bool backFaceCulling { get; set; }
+
+        [DataMember]
+        public bool wireframe { get; set; }
+
+        [DataMember]
+        public float alpha { get; set; }
+
+
+        public BabylonMaterial()
+        {
+            backFaceCulling = true;
+
+            alpha = 1.0f;
+        }
+    }
+}

+ 131 - 122
Exporters/3ds Max/BabylonExport.Entities/BabylonMesh.cs

@@ -1,122 +1,131 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonMesh : BabylonAbstractMesh
-    {
-        [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 bool pickable { get; set; }
-
-        [DataMember]
-        public float[] pivotMatrix { 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 bool hasVertexAlpha { 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 bool infiniteDistance { get; set; }
-        
-        [DataMember]
-        public int billboardMode { get; set; }
-
-        [DataMember]
-        public float visibility { get; set; }
-
-        [DataMember]
-        public BabylonSubMesh[] subMeshes { get; set; }
-
-        [DataMember]
-        public BabylonAbstractMesh[] instances { get; set; }
-
-        [DataMember]
-        public int skeletonId { get; set; }
-
-        [DataMember]
-        public bool showBoundingBox { get; set; }
-
-        [DataMember]
-        public bool showSubMeshesBoundingBox { get; set; }
-
-        [DataMember]
-        public bool applyFog { get; set; }
-
-        [DataMember]
-        public int alphaIndex { get; set; }
-
-        [DataMember]
-        public int physicsImpostor { get; set; }
-
-        [DataMember]
-        public float physicsMass { get; set; }
-
-        [DataMember]
-        public float physicsFriction { get; set; }
-
-        [DataMember]
-        public float physicsRestitution { 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;
-
-            pickable = true;
-        }
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonMesh : BabylonAbstractMesh
+    {
+        [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 bool pickable { get; set; }
+
+        [DataMember]
+        public float[] pivotMatrix { 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 bool hasVertexAlpha { get; set; }
+
+        [DataMember]
+        public int[] matricesIndices { get; set; }
+
+        [DataMember]
+        public float[] matricesWeights { get; set; }
+
+        [DataMember]
+        public int[] matricesIndicesExtra { get; set; }
+
+        [DataMember]
+        public float[] matricesWeightsExtra { get; set; }
+
+        [DataMember]
+        public int[] indices { get; set; }
+
+        [DataMember]
+        public bool checkCollisions { get; set; }
+
+        [DataMember]
+        public bool receiveShadows { get; set; }    
+    
+        [DataMember]
+        public bool infiniteDistance { get; set; }
+        
+        [DataMember]
+        public int billboardMode { get; set; }
+
+        [DataMember]
+        public float visibility { get; set; }
+
+        [DataMember]
+        public BabylonSubMesh[] subMeshes { get; set; }
+
+        [DataMember]
+        public BabylonAbstractMesh[] instances { get; set; }
+
+        [DataMember]
+        public int skeletonId { get; set; }
+
+        [DataMember]
+        public int numBoneInfluencers { get; set; }
+
+        [DataMember]
+        public bool showBoundingBox { get; set; }
+
+        [DataMember]
+        public bool showSubMeshesBoundingBox { get; set; }
+
+        [DataMember]
+        public bool applyFog { get; set; }
+
+        [DataMember]
+        public int alphaIndex { get; set; }
+
+        [DataMember]
+        public int physicsImpostor { get; set; }
+
+        [DataMember]
+        public float physicsMass { get; set; }
+
+        [DataMember]
+        public float physicsFriction { get; set; }
+
+        [DataMember]
+        public float physicsRestitution { 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;
+
+            pickable = true;
+        }
+    }
+}

+ 17 - 17
Exporters/3ds Max/BabylonExport.Entities/BabylonMultiMaterial.cs

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

+ 172 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonPBRMaterial.cs

@@ -0,0 +1,172 @@
+using System.Runtime.Serialization;
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonPBRMaterial : BabylonMaterial
+    {
+        [DataMember]
+        public string customType { get; private set; }
+
+        [DataMember]
+        public float directIntensity { get; set; }
+
+        [DataMember]
+        public float emissiveIntensity { get; set; }
+
+        [DataMember]
+        public float environmentIntensity { get; set; }
+
+        [DataMember]
+        public float specularIntensity { get; set; }
+
+        [DataMember]
+        public float cameraExposure { get; set; }
+
+        [DataMember]
+        public float cameraContrast { get; set; }
+
+        [DataMember]
+        public float microSurface { get; set; }
+
+        [DataMember]
+        public float overloadedShadowIntensity { get; set; }
+
+        [DataMember]
+        public float overloadedShadeIntensity { get; set; }
+
+        [DataMember]
+        public float overloadedAmbientIntensity { get; set; }
+
+        [DataMember]
+        public float overloadedAlbedoIntensity { get; set; }
+
+        [DataMember]
+        public float overloadedReflectivityIntensity { get; set; }
+
+        [DataMember]
+        public float overloadedEmissiveIntensity { get; set; }
+
+        [DataMember]
+        public float[] overloadedAmbient { get; set; }
+
+        [DataMember]
+        public float[] overloadedAlbedo { get; set; }
+
+        [DataMember]
+        public float[] overloadedReflectivity { get; set; }
+
+        [DataMember]
+        public float[] overloadedEmissive { get; set; }
+
+        [DataMember]
+        public float[] overloadedReflection { get; set; }
+
+        [DataMember]
+        public float overloadedMicroSurface { get; set; }
+
+        [DataMember]
+        public float overloadedMicroSurfaceIntensity { get; set; }
+
+        [DataMember]
+        public float overloadedReflectionIntensity { get; set; }
+
+        [DataMember]
+        public BabylonTexture albedoTexture { 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 reflectivityTexture { get; set; }
+
+        [DataMember]
+        public BabylonTexture bumpTexture { get; set; }
+
+        [DataMember]
+        public BabylonTexture lightmapTexture { get; set; }
+
+        [DataMember]
+        public bool useLightmapAsShadowmap { get; set; }
+
+        [DataMember]
+        public BabylonTexture refractionTexture { get; set; }
+
+        [DataMember]
+        public float[] ambient { get; set; }
+
+        [DataMember]
+        public float[] albedo { get; set; }
+
+        [DataMember]
+        public float[] reflectivity { get; set; }
+
+        [DataMember]
+        public float[] reflection { get; set; }
+
+        [DataMember]
+        public float[] emissive { get; set; }
+
+        [DataMember]
+        public bool useAlphaFromAlbedoTexture { get; set; }
+
+        [DataMember]
+        public bool useEmissiveAsIllumination { get; set; }
+
+        [DataMember]
+        public bool useMicroSurfaceFromReflectivityMapAlpha { get; set; }
+
+        [DataMember]
+        public bool useSpecularOverAlpha { get; set; }
+
+        [DataMember]
+        public bool useRadianceOverAlpha { get; set; }
+
+        [DataMember]
+        public float indexOfRefraction { get; set; }
+
+        [DataMember]
+        public bool invertRefractionY { get; set; }
+
+        [DataMember]
+        public BabylonFresnelParameters emissiveFresnelParameters { get; set; }
+
+        [DataMember]
+        public BabylonFresnelParameters opacityFresnelParameters { get; set; }
+
+        public BabylonPBRMaterial() : base()
+        {
+            customType = "BABYLON.PBRMaterial";
+
+            directIntensity = 1.0f;
+            emissiveIntensity = 1.0f;
+            environmentIntensity = 1.0f;
+            specularIntensity = 1.0f;
+            cameraExposure = 1.0f;
+            cameraContrast = 1.0f;
+
+            overloadedShadowIntensity = 1.0f;
+            overloadedShadeIntensity = 1.0f;
+
+            ambient = new[] { 0f, 0f, 0f };
+            albedo = new[] { 0f, 0f, 0f };
+            reflectivity = new[] { 0f, 0f, 0f };
+            reflection = new[] { 0f, 0f, 0f };
+            emissive = new[] { 0f, 0f, 0f };
+
+            overloadedAmbient = new[] { 0f, 0f, 0f };
+            overloadedAlbedo = new[] { 0f, 0f, 0f };
+            overloadedReflectivity = new[] { 0f, 0f, 0f };
+            overloadedEmissive = new[] { 0f, 0f, 0f };
+            overloadedReflection = new[] { 0f, 0f, 0f };
+        }
+    }
+}

+ 86 - 86
Exporters/3ds Max/BabylonExport.Entities/BabylonParticleSystem.cs

@@ -1,86 +1,86 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [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; }
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [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; }
+    }
+}

+ 24 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonProducer.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.Serialization;
+using System.Text;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonProducer
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public string version { get; set; }
+
+        [DataMember]
+        public string exporter_version { get; set; }
+
+        [DataMember]
+        public string file { get; set; }
+    }
+}

+ 194 - 185
Exporters/3ds Max/BabylonExport.Entities/BabylonScene.cs

@@ -1,185 +1,194 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [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 BabylonSound[] sounds { get; set; }
-
-        [DataMember]
-        public BabylonMaterial[] materials { get; set; }
-
-        [DataMember]
-        public BabylonMultiMaterial[] multiMaterials { get; set; }
-
-        [DataMember]
-        public BabylonParticleSystem[] particleSystems { get; set; }
-
-        [DataMember]
-        public BabylonLensFlareSystem[] lensFlareSystems { get; set; }
-
-        [DataMember]
-        public BabylonShadowGenerator[] shadowGenerators { get; set; }
-
-        [DataMember]
-        public BabylonSkeleton[] skeletons { get; set; }
-
-        [DataMember]
-        public BabylonActions actions { get; set; }
-
-        public BabylonVector3 MaxVector { get; set; }
-        public BabylonVector3 MinVector { get; set; }
-
-        public string OutputPath { get; private set; }
-
-        public List<BabylonMesh> MeshesList { get; private set; }
-        public List<BabylonSound> SoundsList { get; private set; }
-        public List<BabylonCamera> CamerasList { get; private set; }
-        public List<BabylonLight> LightsList { get; private set; }
-        public List<BabylonMaterial> MaterialsList { get; private set; }
-        public List<BabylonMultiMaterial> MultiMaterialsList { get; private set; }
-        public List<BabylonShadowGenerator> ShadowGeneratorsList { get; private set; }
-        public 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>();
-            SoundsList = new List<BabylonSound>();
-
-            // Default values
-            autoClear = true;
-            clearColor = new[] { 0.2f, 0.2f, 0.3f };
-            ambientColor = new[] { 0f, 0f, 0f };
-            gravity = new[] { 0f, 0f, -0.9f };
-
-            MaxVector = new BabylonVector3 { X = float.MinValue, Y = float.MinValue, Z = float.MinValue };
-            MinVector = new BabylonVector3 { X = float.MaxValue, Y = float.MaxValue, Z = float.MaxValue };
-        }
-
-        public void Prepare(bool generateDefaultLight = true)
-        {
-            meshes = MeshesList.ToArray();
-            sounds = SoundsList.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(),
-                    type = 3,
-                    groundColor = new float[] {0, 0, 0},
-                    direction = new[] {0, 1.0f, 0},
-                    intensity = 1
-                };
-
-                LightsList.Add(light);
-            }
-
-            cameras = CamerasList.ToArray();
-            lights = LightsList.ToArray();
-
-            if (activeCameraID == null)
-            {
-                activeCameraID = CamerasList[0].id;
-            }
-        }
-
-        public void AddTexture(string texture)
-        {
-            if (exportedTextures.Contains(texture))
-                return;
-
-            exportedTextures.Add(texture);
-
-            File.Copy(texture, Path.Combine(OutputPath, Path.GetFileName(texture)), true);
-        }
-
-        public bool AddTextureCube(string textureName)
-        {
-            if (exportedTextures.Contains(textureName))
-                return false;
-
-            exportedTextures.Add(textureName);
-
-            return true;
-        }
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonScene
+    {
+        [DataMember]
+        public BabylonProducer producer { get; set; }
+
+        [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 bool physicsEnabled { get; set; }
+
+        [DataMember]
+        public float[] physicsGravity { 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 BabylonSound[] sounds { get; set; }
+
+        [DataMember]
+        public BabylonMaterial[] materials { get; set; }
+
+        [DataMember]
+        public BabylonMultiMaterial[] multiMaterials { get; set; }
+
+        [DataMember]
+        public BabylonParticleSystem[] particleSystems { get; set; }
+
+        [DataMember]
+        public BabylonLensFlareSystem[] lensFlareSystems { get; set; }
+
+        [DataMember]
+        public BabylonShadowGenerator[] shadowGenerators { get; set; }
+
+        [DataMember]
+        public BabylonSkeleton[] skeletons { get; set; }
+
+        [DataMember]
+        public BabylonActions actions { get; set; }
+
+        public BabylonVector3 MaxVector { get; set; }
+        public BabylonVector3 MinVector { get; set; }
+
+        public string OutputPath { get; private set; }
+
+        public List<BabylonMesh> MeshesList { get; private set; }
+        public List<BabylonSound> SoundsList { get; private set; }
+        public List<BabylonCamera> CamerasList { get; private set; }
+        public List<BabylonLight> LightsList { get; private set; }
+        public List<BabylonMaterial> MaterialsList { get; private set; }
+        public List<BabylonMultiMaterial> MultiMaterialsList { get; private set; }
+        public List<BabylonShadowGenerator> ShadowGeneratorsList { get; private set; }
+        public 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>();
+            SoundsList = new List<BabylonSound>();
+
+            // Default values
+            autoClear = true;
+            clearColor = new[] { 0.2f, 0.2f, 0.3f };
+            ambientColor = new[] { 0f, 0f, 0f };
+            gravity = new[] { 0f, 0f, -0.9f };
+
+            MaxVector = new BabylonVector3 { X = float.MinValue, Y = float.MinValue, Z = float.MinValue };
+            MinVector = new BabylonVector3 { X = float.MaxValue, Y = float.MaxValue, Z = float.MaxValue };
+        }
+
+        public void Prepare(bool generateDefaultLight = true)
+        {
+            meshes = MeshesList.ToArray();
+            sounds = SoundsList.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(),
+                    type = 3,
+                    groundColor = new float[] {0, 0, 0},
+                    direction = new[] {0, 1.0f, 0},
+                    intensity = 1
+                };
+
+                LightsList.Add(light);
+            }
+
+            cameras = CamerasList.ToArray();
+            lights = LightsList.ToArray();
+
+            if (activeCameraID == null)
+            {
+                activeCameraID = CamerasList[0].id;
+            }
+        }
+
+        public void AddTexture(string texture)
+        {
+            if (exportedTextures.Contains(texture))
+                return;
+
+            exportedTextures.Add(texture);
+
+            File.Copy(texture, Path.Combine(OutputPath, Path.GetFileName(texture)), true);
+        }
+
+        public bool AddTextureCube(string textureName)
+        {
+            if (exportedTextures.Contains(textureName))
+                return false;
+
+            exportedTextures.Add(textureName);
+
+            return true;
+        }
+    }
+}

+ 39 - 36
Exporters/3ds Max/BabylonExport.Entities/BabylonShadowGenerator.cs

@@ -1,36 +1,39 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonShadowGenerator
-    {
-        [DataMember]
-        public int mapSize { get; set; }
-
-        [DataMember]
-        public float bias { get; set; }
-
-        [DataMember]
-        public string lightId { get; set; }
-
-        [DataMember]
-        public bool useVarianceShadowMap { get; set; }
-
-        [DataMember]
-        public bool usePoissonSampling { get; set; }
-
-        [DataMember]
-        public bool useBlurVarianceShadowMap { get; set; }
-
-        [DataMember]
-        public float blurScale { get; set; }
-
-        [DataMember]
-        public float blurBoxOffset { get; set; }
-
-        [DataMember]
-        public string[] renderList { get; set; }
-
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonShadowGenerator
+    {
+        [DataMember]
+        public int mapSize { get; set; }
+
+        [DataMember]
+        public float bias { get; set; }
+
+        [DataMember]
+        public string lightId { get; set; }
+
+        [DataMember]
+        public bool useVarianceShadowMap { get; set; }
+
+        [DataMember]
+        public bool usePoissonSampling { get; set; }
+
+        [DataMember]
+        public bool useBlurVarianceShadowMap { get; set; }
+
+        [DataMember]
+        public float blurScale { get; set; }
+
+        [DataMember]
+        public float blurBoxOffset { get; set; }
+
+        [DataMember]
+        public string[] renderList { get; set; }
+
+        [DataMember]
+        public bool forceBackFacesOnly { get; set; }
+
+    }
+}

+ 20 - 17
Exporters/3ds Max/BabylonExport.Entities/BabylonSkeleton.cs

@@ -1,17 +1,20 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonSkeleton
-    {
-        [DataMember]
-        public int id { get; set; }
-        
-        [DataMember]
-        public string name { get; set; }
-
-        [DataMember]
-        public BabylonBone[] bones { get; set; }
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonSkeleton
+    {
+        [DataMember]
+        public int id { get; set; }
+        
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public BabylonBone[] bones { get; set; }
+
+        [DataMember]
+        public bool needInitialSkinMatrix { get; set; }
+    }
+}

+ 86 - 86
Exporters/3ds Max/BabylonExport.Entities/BabylonSound.cs

@@ -1,86 +1,86 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonSound
-    {
-        [DataMember]
-        public string name { get; set; }
-
-        [DataMember]
-        public float volume { get; set; }
-
-        [DataMember]
-        public float playbackRate { get; set; }
-
-        [DataMember]
-        public bool autoplay { get; set; }
-
-        [DataMember]
-        public bool loop { get; set; }
-
-        [DataMember]
-        public int soundTrackId { get; set; }
-
-        [DataMember]
-        public bool spatialSound { get; set; }
-
-        [DataMember]
-        public float[] position { get; set; }
-
-        [DataMember]
-        public float refDistance { get; set; }
-
-        [DataMember]
-        public float rolloffFactor { get; set; }
-
-        [DataMember]
-        public float maxDistance { get; set; }
-
-        [DataMember]
-        public string distanceModel { get; set; }
-
-        [DataMember]
-        public string panningModel { get; set; }
-
-        [DataMember]
-        public bool isDirectional { get; set; }
-
-        [DataMember]
-        public float coneInnerAngle { get; set; }
-
-        [DataMember]
-        public float coneOuterAngle { get; set; }
-
-        [DataMember]
-        public float coneOuterGain { get; set; }
-
-        [DataMember]
-        public string connectedMeshId { get; set; }
-
-        [DataMember]
-        public float[] localDirectionToMesh { get; set; }
-
-        public BabylonSound()
-        {
-            volume = 1;
-            playbackRate = 1;
-            autoplay = false;
-            loop = false;
-            soundTrackId = -1;
-            spatialSound = false;
-            position = new[] { 0f, 0f, 0f };
-            refDistance = 1;
-            rolloffFactor = 1;
-            maxDistance = 100;
-            distanceModel = "linear";
-            panningModel = "equalpower";
-            isDirectional = false;
-            coneInnerAngle = 360;
-            coneOuterAngle = 360;
-            coneOuterGain = 0;
-            localDirectionToMesh = new[] { 1f, 0f, 0f };
-        }
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonSound
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public float volume { get; set; }
+
+        [DataMember]
+        public float playbackRate { get; set; }
+
+        [DataMember]
+        public bool autoplay { get; set; }
+
+        [DataMember]
+        public bool loop { get; set; }
+
+        [DataMember]
+        public int soundTrackId { get; set; }
+
+        [DataMember]
+        public bool spatialSound { get; set; }
+
+        [DataMember]
+        public float[] position { get; set; }
+
+        [DataMember]
+        public float refDistance { get; set; }
+
+        [DataMember]
+        public float rolloffFactor { get; set; }
+
+        [DataMember]
+        public float maxDistance { get; set; }
+
+        [DataMember]
+        public string distanceModel { get; set; }
+
+        [DataMember]
+        public string panningModel { get; set; }
+
+        [DataMember]
+        public bool isDirectional { get; set; }
+
+        [DataMember]
+        public float coneInnerAngle { get; set; }
+
+        [DataMember]
+        public float coneOuterAngle { get; set; }
+
+        [DataMember]
+        public float coneOuterGain { get; set; }
+
+        [DataMember]
+        public string connectedMeshId { get; set; }
+
+        [DataMember]
+        public float[] localDirectionToMesh { get; set; }
+
+        public BabylonSound()
+        {
+            volume = 1;
+            playbackRate = 1;
+            autoplay = false;
+            loop = false;
+            soundTrackId = -1;
+            spatialSound = false;
+            position = new[] { 0f, 0f, 0f };
+            refDistance = 1;
+            rolloffFactor = 1;
+            maxDistance = 100;
+            distanceModel = "linear";
+            panningModel = "equalpower";
+            isDirectional = false;
+            coneInnerAngle = 360;
+            coneOuterAngle = 360;
+            coneOuterGain = 0;
+            localDirectionToMesh = new[] { 1f, 0f, 0f };
+        }
+    }
+}

+ 72 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonStandardMaterial.cs

@@ -0,0 +1,72 @@
+using System.Runtime.Serialization;
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonStandardMaterial: BabylonMaterial
+    {
+        [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 BabylonTexture diffuseTexture { get; set; }
+
+        [DataMember]
+        public BabylonFresnelParameters diffuseFresnelParameters { get; set; }
+
+        [DataMember]
+        public BabylonTexture ambientTexture { get; set; }
+
+        [DataMember]
+        public BabylonTexture opacityTexture { get; set; }
+
+        [DataMember]
+        public BabylonFresnelParameters opacityFresnelParameters { get; set; }
+
+        [DataMember]
+        public BabylonTexture reflectionTexture { get; set; }
+
+        [DataMember]
+        public BabylonFresnelParameters reflectionFresnelParameters { get; set; }
+
+        [DataMember]
+        public BabylonTexture emissiveTexture { get; set; }
+        [DataMember]
+        public BabylonTexture lightmapTexture { get; set; }
+        [DataMember]
+        public bool useLightmapAsShadowmap { get; set; }
+
+        [DataMember]
+        public BabylonFresnelParameters emissiveFresnelParameters { get; set; }
+
+        [DataMember]
+        public BabylonTexture specularTexture { get; set; }
+
+        [DataMember]
+        public BabylonTexture bumpTexture { get; set; }
+
+        [DataMember]
+        public bool useSpecularOverAlpha { get; set; }
+
+        public BabylonStandardMaterial() : base()
+        {
+            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;
+            useSpecularOverAlpha = true;
+        }
+    }
+}

+ 24 - 24
Exporters/3ds Max/BabylonExport.Entities/BabylonSubMesh.cs

@@ -1,24 +1,24 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [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; }
-
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [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; }
+
+    }
+}

+ 87 - 87
Exporters/3ds Max/BabylonExport.Entities/BabylonTexture.cs

@@ -1,87 +1,87 @@
-using System.Runtime.Serialization;
-
-namespace BabylonExport.Entities
-{
-    [DataContract]
-    public class BabylonTexture
-    {
-        [DataMember]
-        public string name { get; set; }
-
-        [DataMember]
-        public float level { get; set; }
-
-        [DataMember]
-        public bool hasAlpha { get; set; }
-
-        [DataMember]
-        public bool getAlphaFromRGB { 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;
-        }
-    }
-}
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonTexture
+    {
+        [DataMember]
+        public string name { get; set; }
+
+        [DataMember]
+        public float level { get; set; }
+
+        [DataMember]
+        public bool hasAlpha { get; set; }
+
+        [DataMember]
+        public bool getAlphaFromRGB { 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;
+        }
+    }
+}

+ 36 - 36
Exporters/3ds Max/BabylonExport.Entities/BabylonVector3.cs

@@ -1,36 +1,36 @@
-using System;
-
-namespace BabylonExport.Entities
-{
-    public class BabylonVector3
-    {
-        public float X { get; set; }
-        public float Y { get; set; }
-        public float Z { get; set; }
-
-        public float[] ToArray()
-        {
-            return new [] {X, Y, Z};
-        }
-
-        public float Length()
-        {
-            return (float)Math.Sqrt(X * X + Y * Y + Z * Z);
-        }
-
-        public static BabylonVector3 operator +(BabylonVector3 a, BabylonVector3 b)
-        {
-            return new BabylonVector3 {X = a.X + b.X, Y = a.Y + b.Y, Z = a.Z + b.Z};
-        }
-
-        public static BabylonVector3 operator -(BabylonVector3 a, BabylonVector3 b)
-        {
-            return new BabylonVector3 { X = a.X - b.X, Y = a.Y - b.Y, Z = a.Z - b.Z };
-        }
-
-        public static BabylonVector3 operator /(BabylonVector3 a, float b)
-        {
-            return new BabylonVector3 { X = a.X / b, Y = a.Y / b, Z = a.Z / b };
-        }
-    }
-}
+using System;
+
+namespace BabylonExport.Entities
+{
+    public class BabylonVector3
+    {
+        public float X { get; set; }
+        public float Y { get; set; }
+        public float Z { get; set; }
+
+        public float[] ToArray()
+        {
+            return new [] {X, Y, Z};
+        }
+
+        public float Length()
+        {
+            return (float)Math.Sqrt(X * X + Y * Y + Z * Z);
+        }
+
+        public static BabylonVector3 operator +(BabylonVector3 a, BabylonVector3 b)
+        {
+            return new BabylonVector3 {X = a.X + b.X, Y = a.Y + b.Y, Z = a.Z + b.Z};
+        }
+
+        public static BabylonVector3 operator -(BabylonVector3 a, BabylonVector3 b)
+        {
+            return new BabylonVector3 { X = a.X - b.X, Y = a.Y - b.Y, Z = a.Z - b.Z };
+        }
+
+        public static BabylonVector3 operator /(BabylonVector3 a, float b)
+        {
+            return new BabylonVector3 { X = a.X / b, Y = a.Y / b, Z = a.Z / b };
+        }
+    }
+}

BIN=BIN
Exporters/3ds Max/Max2Babylon-0.24.zip


BIN=BIN
Exporters/3ds Max/Max2Babylon-0.5.0.zip


+ 277 - 0
Exporters/3ds Max/Max2Babylon/2017/Max2Babylon2017.csproj

@@ -0,0 +1,277 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.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>{2F49C726-A1F8-40D4-859F-1355949608DC}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Max2Babylon</RootNamespace>
+    <AssemblyName>Max2Babylon</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <TargetFrameworkProfile />
+    <SccProjectName>SAK</SccProjectName>
+    <SccLocalPath>SAK</SccLocalPath>
+    <SccAuxPath>SAK</SccAuxPath>
+    <SccProvider>SAK</SccProvider>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+    <RestorePackages>true</RestorePackages>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>C:\Program Files\Autodesk\3ds Max 2017\bin\assemblies\</OutputPath>
+    <DefineConstants>TRACE;DEBUG;MAX2017</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>C:\Program Files\Autodesk\3ds Max 2013\bin\assemblies\</OutputPath>
+    <DefineConstants>TRACE;MAX2015</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Autodesk.Max, Version=17.0.630.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\..\Repos\Babylon.js\Exporters\3ds Max\Max2Babylon\2015\Refs\Autodesk.Max.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="SharpDX, Version=2.4.2.0, Culture=neutral, PublicKeyToken=627a3d6d1956f55a, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\BabylonExport.Core\Refs\SharpDX.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Runtime.Serialization" />
+    <Reference Include="System.Web" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="..\BabylonActionCallback.cs">
+      <Link>BabylonActionCallback.cs</Link>
+    </Compile>
+    <Compile Include="..\BabylonExportActionItem.cs">
+      <Link>BabylonExportActionItem.cs</Link>
+    </Compile>
+    <Compile Include="..\BabylonPropertiesActionItem.cs">
+      <Link>BabylonPropertiesActionItem.cs</Link>
+    </Compile>
+    <Compile Include="..\Descriptor.cs">
+      <Link>Descriptor.cs</Link>
+    </Compile>
+    <Compile Include="..\Exporter\ActionBuilder\BabylonActionsBuilderActionItem.cs">
+      <Link>Exporter\ActionBuilder\BabylonActionsBuilderActionItem.cs</Link>
+    </Compile>
+    <Compile Include="..\Exporter\ActionBuilder\BabylonExporter.Action.cs">
+      <Link>Exporter\ActionBuilder\BabylonExporter.Action.cs</Link>
+    </Compile>
+    <Compile Include="..\Exporter\BabylonExporter.Animation.cs">
+      <Link>Exporter\BabylonExporter.Animation.cs</Link>
+    </Compile>
+    <Compile Include="..\Exporter\BabylonExporter.Camera.cs">
+      <Link>Exporter\BabylonExporter.Camera.cs</Link>
+    </Compile>
+    <Compile Include="..\Exporter\BabylonExporter.cs">
+      <Link>Exporter\BabylonExporter.cs</Link>
+    </Compile>
+    <Compile Include="..\Exporter\BabylonExporter.Light.cs">
+      <Link>Exporter\BabylonExporter.Light.cs</Link>
+    </Compile>
+    <Compile Include="..\Exporter\BabylonExporter.Material.cs">
+      <Link>Exporter\BabylonExporter.Material.cs</Link>
+    </Compile>
+    <Compile Include="..\Exporter\BabylonExporter.Mesh.cs">
+      <Link>Exporter\BabylonExporter.Mesh.cs</Link>
+    </Compile>
+    <Compile Include="..\Exporter\BabylonExporter.ShadowGenerator.cs">
+      <Link>Exporter\BabylonExporter.ShadowGenerator.cs</Link>
+    </Compile>
+    <Compile Include="..\Exporter\BabylonExporter.Skeleton.cs">
+      <Link>Exporter\BabylonExporter.Skeleton.cs</Link>
+    </Compile>
+    <Compile Include="..\Exporter\BabylonExporter.Texture.cs">
+      <Link>Exporter\BabylonExporter.Texture.cs</Link>
+    </Compile>
+    <Compile Include="..\Exporter\GlobalVertex.cs">
+      <Link>Exporter\GlobalVertex.cs</Link>
+    </Compile>
+    <Compile Include="..\Forms\ActionsBuilderForm.cs">
+      <Link>Forms\ActionsBuilderForm.cs</Link>
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="..\Forms\ActionsBuilderForm.designer.cs">
+      <Link>Forms\ActionsBuilderForm.designer.cs</Link>
+      <DependentUpon>ActionsBuilderForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="..\Forms\CameraPropertiesForm.cs">
+      <Link>Forms\CameraPropertiesForm.cs</Link>
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="..\Forms\CameraPropertiesForm.Designer.cs">
+      <Link>Forms\CameraPropertiesForm.Designer.cs</Link>
+      <DependentUpon>CameraPropertiesForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="..\Forms\ExporterForm.cs">
+      <Link>Forms\ExporterForm.cs</Link>
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="..\Forms\ExporterForm.Designer.cs">
+      <Link>Forms\ExporterForm.Designer.cs</Link>
+      <DependentUpon>ExporterForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="..\Forms\LightPropertiesForm.cs">
+      <Link>Forms\LightPropertiesForm.cs</Link>
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="..\Forms\LightPropertiesForm.Designer.cs">
+      <Link>Forms\LightPropertiesForm.Designer.cs</Link>
+      <DependentUpon>LightPropertiesForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="..\Forms\ObjectPropertiesForm.cs">
+      <Link>Forms\ObjectPropertiesForm.cs</Link>
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="..\Forms\ObjectPropertiesForm.Designer.cs">
+      <Link>Forms\ObjectPropertiesForm.Designer.cs</Link>
+      <DependentUpon>ObjectPropertiesForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="..\Forms\ScenePropertiesForm.cs">
+      <Link>Forms\ScenePropertiesForm.cs</Link>
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="..\Forms\ScenePropertiesForm.Designer.cs">
+      <Link>Forms\ScenePropertiesForm.Designer.cs</Link>
+      <DependentUpon>ScenePropertiesForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="..\Forms\Vector3Control.cs">
+      <Link>Forms\Vector3Control.cs</Link>
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="..\Forms\Vector3Control.Designer.cs">
+      <Link>Forms\Vector3Control.Designer.cs</Link>
+      <DependentUpon>Vector3Control.cs</DependentUpon>
+    </Compile>
+    <Compile Include="..\GlobalUtility.cs">
+      <Link>GlobalUtility.cs</Link>
+    </Compile>
+    <Compile Include="..\JsonTextWriterOptimized.cs">
+      <Link>JsonTextWriterOptimized.cs</Link>
+    </Compile>
+    <Compile Include="..\Loader.cs">
+      <Link>Loader.cs</Link>
+    </Compile>
+    <Compile Include="..\Tools\Tools.cs">
+      <Link>Tools\Tools.cs</Link>
+    </Compile>
+    <Compile Include="..\Tools\VNormal.cs">
+      <Link>Tools\VNormal.cs</Link>
+    </Compile>
+    <Compile Include="..\Tools\WebServer.cs">
+      <Link>Tools\WebServer.cs</Link>
+    </Compile>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Refs\Autodesk.Max.dll" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="..\Forms\ActionsBuilderForm.resx">
+      <Link>Forms\ActionsBuilderForm.resx</Link>
+      <DependentUpon>ActionsBuilderForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="..\Forms\CameraPropertiesForm.resx">
+      <Link>Forms\CameraPropertiesForm.resx</Link>
+      <DependentUpon>CameraPropertiesForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="..\Forms\ExporterForm.resx">
+      <Link>Forms\ExporterForm.resx</Link>
+      <DependentUpon>ExporterForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="..\Forms\LightPropertiesForm.resx">
+      <Link>Forms\LightPropertiesForm.resx</Link>
+      <DependentUpon>LightPropertiesForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="..\Forms\ObjectPropertiesForm.resx">
+      <Link>Forms\ObjectPropertiesForm.resx</Link>
+      <DependentUpon>ObjectPropertiesForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="..\Forms\ScenePropertiesForm.resx">
+      <Link>Forms\ScenePropertiesForm.resx</Link>
+      <DependentUpon>ScenePropertiesForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="..\Forms\Vector3Control.resx">
+      <Link>Forms\Vector3Control.resx</Link>
+      <DependentUpon>Vector3Control.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\BabylonExport.Entities\BabylonExport.Entities.csproj">
+      <Project>{6150965a-658c-4263-89ad-4f980eb0675d}</Project>
+      <Name>BabylonExport.Entities</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\BabylonFileConverter\BabylonFileConverter.csproj">
+      <Project>{a6b76356-1d1c-4c82-8199-a6406da85a95}</Project>
+      <Name>BabylonFileConverter</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <WCFMetadata Include="Service References\" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
+  </Target>
+  <PropertyGroup>
+    <PostBuildEvent>mkdir "$(OutDir)BabylonActionsBuilder"
+mkdir "$(OutDir)BabylonActionsBuilder\fonts"
+mkdir "$(OutDir)BabylonActionsBuilder\fonts\SinkinSans"
+copy "$(SolutionDir)ActionsBuilder\Sources\fonts.css" "$(OutDir)BabylonActionsBuilder\fonts.css"
+copy "$(SolutionDir)ActionsBuilder\Sources\index.css" "$(OutDir)BabylonActionsBuilder\index.css"
+copy "$(SolutionDir)ActionsBuilder\Sources\index.html" "$(OutDir)BabylonActionsBuilder\index.html"
+copy "$(SolutionDir)ActionsBuilder\Sources\actionsbuilder.max.js" "$(OutDir)BabylonActionsBuilder\actionsbuilder.max.js"
+copy "$(SolutionDir)ActionsBuilder\Sources\raphael.js" "$(OutDir)BabylonActionsBuilder\raphael.js"
+copy "$(SolutionDir)babylon.max.js" "$(OutDir)BabylonActionsBuilder\babylon.max.js"
+copy "$(SolutionDir)ActionsBuilder\Sources\fonts\SinkinSans\" "$(OutDir)BabylonActionsBuilder\fonts\SinkinSans\"</PostBuildEvent>
+  </PropertyGroup>
+  <!-- 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>

+ 36 - 0
Exporters/3ds Max/Max2Babylon/2017/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+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("Max2Babylon")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Max2Babylon")]
+[assembly: AssemblyCopyright("Copyright ©  2014")]
+[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("2d621b1c-3661-49bd-8dd3-4c5de51fce94")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 63 - 0
Exporters/3ds Max/Max2Babylon/2017/Properties/Resources.Designer.cs

@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.34014
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Max2Babylon.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Max2Babylon.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+    }
+}

+ 120 - 0
Exporters/3ds Max/Max2Babylon/2017/Properties/Resources.resx

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

BIN=BIN
Exporters/3ds Max/Max2Babylon/2017/Refs/Autodesk.Max.dll


+ 8 - 8
Exporters/3ds Max/Max2Babylon/BabylonActionCallback.cs

@@ -1,8 +1,8 @@
-using Autodesk.Max.Plugins;
-
-namespace Max2Babylon
-{
-    class BabylonActionCallback : ActionCallback
-    {
-    }
-}
+using Autodesk.Max.Plugins;
+
+namespace Max2Babylon
+{
+    class BabylonActionCallback : ActionCallback
+    {
+    }
+}

+ 71 - 71
Exporters/3ds Max/Max2Babylon/BabylonExportActionItem.cs

@@ -1,71 +1,71 @@
-using System.Windows.Forms;
-using ActionItem = Autodesk.Max.Plugins.ActionItem;
-
-namespace Max2Babylon
-{
-    public class BabylonExportActionItem : ActionItem
-    {
-        private ExporterForm form;
-
-        public override bool ExecuteAction()
-        {
-            if (form == null)
-                form = new ExporterForm(this);
-            form.Show();
-            form.BringToFront();
-            form.WindowState = FormWindowState.Normal;
-
-            return true;
-        }
-
-        public void Close()
-        {
-            if (form == null)
-            {
-                return;
-            }
-            form.Dispose();
-            form = null;
-        }
-
-        public override int Id_
-        {
-            get { return 1; }
-        }
-
-        public override string ButtonText
-        {
-            get { return "Babylon File Exporter"; }
-        }
-
-        public override string MenuText
-        {
-            get { return "&Babylon File Exporter..."; }
-        }
-
-        public override string DescriptionText
-        {
-            get { return "Generate a babylon.js scene file2"; }
-        }
-
-        public override string CategoryText
-        {
-            get { return "Babylon"; }
-        }
-
-        public override bool IsChecked_
-        {
-            get { return false; }
-        }
-
-        public override bool IsItemVisible
-        {
-            get { return true; }
-        }
-
-        public override bool IsEnabled_
-        {
-            get { return true; }
-        }
-    }
-}
+using System.Windows.Forms;
+using ActionItem = Autodesk.Max.Plugins.ActionItem;
+
+namespace Max2Babylon
+{
+    public class BabylonExportActionItem : ActionItem
+    {
+        private ExporterForm form;
+
+        public override bool ExecuteAction()
+        {
+            if (form == null)
+                form = new ExporterForm(this);
+            form.Show();
+            form.BringToFront();
+            form.WindowState = FormWindowState.Normal;
+
+            return true;
+        }
+
+        public void Close()
+        {
+            if (form == null)
+            {
+                return;
+            }
+            form.Dispose();
+            form = null;
+        }
+
+        public override int Id_
+        {
+            get { return 1; }
+        }
+
+        public override string ButtonText
+        {
+            get { return "Babylon File Exporter"; }
+        }
+
+        public override string MenuText
+        {
+            get { return "&Babylon File Exporter..."; }
+        }
+
+        public override string DescriptionText
+        {
+            get { return "Generate a babylon.js scene file2"; }
+        }
+
+        public override string CategoryText
+        {
+            get { return "Babylon"; }
+        }
+
+        public override bool IsChecked_
+        {
+            get { return false; }
+        }
+
+        public override bool IsItemVisible
+        {
+            get { return true; }
+        }
+
+        public override bool IsEnabled_
+        {
+            get { return true; }
+        }
+    }
+}

+ 91 - 91
Exporters/3ds Max/Max2Babylon/BabylonPropertiesActionItem.cs

@@ -1,91 +1,91 @@
-using Autodesk.Max;
-using ActionItem = Autodesk.Max.Plugins.ActionItem;
-
-namespace Max2Babylon
-{
-    public class BabylonPropertiesActionItem : ActionItem
-    {
-        public override bool ExecuteAction()
-        {
-            if (Loader.Core.SelNodeCount == 0)
-            {
-                using (var frm = new ScenePropertiesForm())
-                {
-                    frm.ShowDialog();
-                    return true;
-                }
-            }
-
-            var firstNode = Loader.Core.GetSelNode(0);
-
-            if (firstNode.ObjectRef != null && firstNode.ObjectRef.Eval(0).Obj.SuperClassID == SClass_ID.Camera)
-            {
-                using (var frm = new CameraPropertiesForm())
-                {
-                    frm.ShowDialog();
-                    return true;
-                }
-            }
-
-           
-
-            if (firstNode.ObjectRef != null && firstNode.ObjectRef.Eval(0).Obj.SuperClassID == SClass_ID.Light)
-            {
-                using (var frm = new LightPropertiesForm())
-                {
-                    frm.ShowDialog();
-                    return true;
-                }
-            }
-           
-            // consider non-recognized objects as meshes so they can be animated intermediate nodes
-            using (var frm = new ObjectPropertiesForm())
-            {
-                frm.ShowDialog();
-                return true;
-            }
-            
-
-        }
-
-        public override int Id_
-        {
-            get { return 1; }
-        }
-
-        public override string ButtonText
-        {
-            get { return "Babylon Properties"; }
-        }
-
-        public override string MenuText
-        {
-            get { return "Babylon Properties"; }
-        }
-
-        public override string DescriptionText
-        {
-            get { return "UI for setting Babylon.js specific properties"; }
-        }
-
-        public override string CategoryText
-        {
-            get { return "Babylon"; }
-        }
-
-        public override bool IsChecked_
-        {
-            get { return false; }
-        }
-
-        public override bool IsItemVisible
-        {
-            get { return true; }
-        }
-
-        public override bool IsEnabled_
-        {
-            get { return true; }
-        }
-    }
-}
+using Autodesk.Max;
+using ActionItem = Autodesk.Max.Plugins.ActionItem;
+
+namespace Max2Babylon
+{
+    public class BabylonPropertiesActionItem : ActionItem
+    {
+        public override bool ExecuteAction()
+        {
+            if (Loader.Core.SelNodeCount == 0)
+            {
+                using (var frm = new ScenePropertiesForm())
+                {
+                    frm.ShowDialog();
+                    return true;
+                }
+            }
+
+            var firstNode = Loader.Core.GetSelNode(0);
+
+            if (firstNode.ObjectRef != null && firstNode.ObjectRef.Eval(0).Obj.SuperClassID == SClass_ID.Camera)
+            {
+                using (var frm = new CameraPropertiesForm())
+                {
+                    frm.ShowDialog();
+                    return true;
+                }
+            }
+
+           
+
+            if (firstNode.ObjectRef != null && firstNode.ObjectRef.Eval(0).Obj.SuperClassID == SClass_ID.Light)
+            {
+                using (var frm = new LightPropertiesForm())
+                {
+                    frm.ShowDialog();
+                    return true;
+                }
+            }
+           
+            // consider non-recognized objects as meshes so they can be animated intermediate nodes
+            using (var frm = new ObjectPropertiesForm())
+            {
+                frm.ShowDialog();
+                return true;
+            }
+            
+
+        }
+
+        public override int Id_
+        {
+            get { return 1; }
+        }
+
+        public override string ButtonText
+        {
+            get { return "Babylon Properties"; }
+        }
+
+        public override string MenuText
+        {
+            get { return "Babylon Properties"; }
+        }
+
+        public override string DescriptionText
+        {
+            get { return "UI for setting Babylon.js specific properties"; }
+        }
+
+        public override string CategoryText
+        {
+            get { return "Babylon"; }
+        }
+
+        public override bool IsChecked_
+        {
+            get { return false; }
+        }
+
+        public override bool IsItemVisible
+        {
+            get { return true; }
+        }
+
+        public override bool IsEnabled_
+        {
+            get { return true; }
+        }
+    }
+}

+ 52 - 52
Exporters/3ds Max/Max2Babylon/Descriptor.cs

@@ -1,52 +1,52 @@
-using Autodesk.Max;
-
-namespace Max2Babylon
-{
-    public class Descriptor : Autodesk.Max.Plugins.ClassDesc2
-    {
-        public override object Create(bool loading)
-        {
-            return new GlobalUtility();
-        }
-
-        public override bool IsPublic
-        {
-            get
-            {
-                return true;
-            }
-        }
-
-        public override string ClassName
-        {
-            get
-            {
-                return "Babylon File Exporter";
-            }
-        }
-
-        public override SClass_ID SuperClassID
-        {
-            get
-            {
-                return SClass_ID.Gup;
-            }
-        }
-
-        public override IClass_ID ClassID
-        {
-            get
-            {
-                return Loader.Class_ID;
-            }
-        }
-
-        public override string Category
-        {
-            get
-            {
-                return "Babylon";
-            }
-        }
-    }
-}
+using Autodesk.Max;
+
+namespace Max2Babylon
+{
+    public class Descriptor : Autodesk.Max.Plugins.ClassDesc2
+    {
+        public override object Create(bool loading)
+        {
+            return new GlobalUtility();
+        }
+
+        public override bool IsPublic
+        {
+            get
+            {
+                return true;
+            }
+        }
+
+        public override string ClassName
+        {
+            get
+            {
+                return "Babylon File Exporter";
+            }
+        }
+
+        public override SClass_ID SuperClassID
+        {
+            get
+            {
+                return SClass_ID.Gup;
+            }
+        }
+
+        public override IClass_ID ClassID
+        {
+            get
+            {
+                return Loader.Class_ID;
+            }
+        }
+
+        public override string Category
+        {
+            get
+            {
+                return "Babylon";
+            }
+        }
+    }
+}

+ 315 - 309
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Animation.cs

@@ -1,309 +1,315 @@
-using System;
-using System.Collections.Generic;
-using Autodesk.Max;
-using BabylonExport.Entities;
-
-namespace Max2Babylon
-{
-    partial class BabylonExporter
-    {
-        const int Ticks = 160;
-
-        private static BabylonAnimationKey GenerateFloatFunc(int index, IIKeyControl keyControl)
-        {
-            var key = Loader.Global.ILinFloatKey.Create();
-            keyControl.GetKey(index, key);
-
-            return new BabylonAnimationKey
-            {
-                frame = key.Time / Ticks,
-                values = new[] { key.Val }
-            };
-        }
-
-        private static bool ExportFloatController(IControl control, string property, List<BabylonAnimation> animations)
-        {
-            return ExportController(control, property, animations, 0x2001, BabylonAnimation.DataType.Float, GenerateFloatFunc);
-        }
-
-        private static bool ExportQuaternionController(IControl control, string property, List<BabylonAnimation> animations)
-        {
-            IQuat previousQuat = null;
-
-            return ExportController(control, property, animations, 0x2003, BabylonAnimation.DataType.Quaternion,
-                (index, keyControl) =>
-                {
-                    var key = Loader.Global.ILinRotKey.Create();
-                    keyControl.GetKey(index, key);
-                    var newQuat = key.Val;
-
-                    if (index > 0)
-                    {
-                        newQuat = previousQuat.Multiply(newQuat);
-                    }
-
-                    previousQuat = newQuat;
-
-                    return new BabylonAnimationKey
-                    {
-                        frame = key.Time / Ticks,
-                        values = newQuat.ToArray()
-                    };
-                });
-        }
-
-        private static bool ExportVector3Controller(IControl control, string property, List<BabylonAnimation> animations)
-        {
-            var result = false;
-
-            if (control == null)
-            {
-                return false;
-            }
-
-            if (control.XController != null || control.YController != null || control.ZController != null)
-            {
-                result |= ExportFloatController(control.XController, property + ".x", animations);
-                result |= ExportFloatController(control.ZController, property + ".y", animations);
-                result |= ExportFloatController(control.YController, property + ".z", animations);
-
-                return result;
-            }
-
-            if (ExportController(control, property, animations, 0x2002, BabylonAnimation.DataType.Vector3,
-                (index, keyControl) =>
-                {
-                    var key = Loader.Global.ILinPoint3Key.Create();
-                    keyControl.GetKey(index, key);
-
-                    return new BabylonAnimationKey
-                    {
-                        frame = key.Time / Ticks,
-                        values = key.Val.ToArraySwitched()
-                    };
-                }))
-            {
-                return true;
-            }
-
-            return ExportController(control, property, animations, 0x2004, BabylonAnimation.DataType.Vector3,
-                (index, keyControl) =>
-                {
-                    var key = Loader.Global.ILinScaleKey.Create();
-                    keyControl.GetKey(index, key);
-
-                    return new BabylonAnimationKey
-                    {
-                        frame = key.Time / Ticks,
-                        values = key.Val.S.ToArraySwitched()
-                    };
-                });
-        }
-
-        private static bool ExportController(IControl control, string property, List<BabylonAnimation> animations, uint classId, BabylonAnimation.DataType dataType, Func<int, IIKeyControl, BabylonAnimationKey> generateFunc)
-        {
-            if (control == null)
-            {
-                return false;
-            }
-
-            var keyControl = control.GetInterface(InterfaceID.Keycontrol) as IIKeyControl;
-
-            if (keyControl == null)
-            {
-                return false;
-            }
-
-            if (control.ClassID.PartA != classId)
-            {
-                return false;
-            }
-
-            var keys = new List<BabylonAnimationKey>();
-            BabylonAnimation.LoopBehavior loopBehavior;
-
-            switch (control.GetORT(2))
-            {
-                case 2:
-                    loopBehavior = BabylonAnimation.LoopBehavior.Cycle;
-                    break;
-                default:
-                    loopBehavior = BabylonAnimation.LoopBehavior.Relative;
-                    break;
-            }
-
-            for (var index = 0; index < keyControl.NumKeys; index++)
-            {
-                keys.Add(generateFunc(index, keyControl));
-            }
-
-            if (keys.Count == 0)
-            {
-                return false;
-            }
-
-            var end = Loader.Core.AnimRange.End;
-            if (keys[keys.Count - 1].frame != end / Ticks)
-            {
-                keys.Add(new BabylonAnimationKey()
-                {
-                    frame = end / Ticks,
-                    values = keys[keys.Count - 1].values
-                });
-            }
-
-            var babylonAnimation = new BabylonAnimation
-            {
-                dataType = (int)dataType,
-                name = property + " animation",
-                keys = keys.ToArray(),
-                framePerSecond = Loader.Global.FrameRate,
-                loopBehavior = (int)loopBehavior,
-                property = property
-            };
-
-            animations.Add(babylonAnimation);
-
-            return true;
-        }
-
-        private static void ExportVector3Animation(string property, List<BabylonAnimation> animations,
-            Func<int, float[]> extractValueFunc)
-        {
-            ExportAnimation(property, animations, extractValueFunc, BabylonAnimation.DataType.Vector3);
-        }
-
-        private static void ExportQuaternionAnimation(string property, List<BabylonAnimation> animations,
-            Func<int, float[]> extractValueFunc)
-        {
-            ExportAnimation(property, animations, extractValueFunc, BabylonAnimation.DataType.Quaternion);
-        }
-
-        private static void ExportFloatAnimation(string property, List<BabylonAnimation> animations,
-            Func<int, float[]> extractValueFunc)
-        {
-            ExportAnimation(property, animations, extractValueFunc, BabylonAnimation.DataType.Float);
-        }
-
-        static void RemoveLinearAnimationKeys(List<BabylonAnimationKey> keys)
-        {
-            for (int ixFirst = keys.Count - 3; ixFirst >= 0; --ixFirst)
-            {
-                while (keys.Count - ixFirst >= 3)
-                {
-                    if (!RemoveAnimationKey(keys, ixFirst))
-                    {
-                        break;
-                    }
-                }
-            }
-        }
-
-        static float[] weightedLerp(int frame0, int frame1, int frame2, float[] value0, float[] value2)
-        {
-            double weight2 = (frame1 - frame0) / (double)(frame2 - frame0);
-            double weight0 = 1 - weight2;
-            float[] result = new float[value0.Length];
-            for (int i = 0; i < result.Length; ++i)
-            {
-                result[i] = (float)(value0[i] * weight0 + value2[i] * weight2);
-            }
-            return result;
-        }
-
-        private static bool RemoveAnimationKey(List<BabylonAnimationKey> keys, int ixFirst)
-        {
-            var first = keys[ixFirst];
-            var middle = keys[ixFirst + 1];
-            var last = keys[ixFirst + 2];
-
-            // first pass, frame equality
-            if (first.values.IsEqualTo(last.values) && first.values.IsEqualTo(middle.values))
-            {
-                keys.RemoveAt(ixFirst + 1);
-                return true;
-            }
-
-            // second pass : linear interpolation detection
-            var computedMiddleValue = weightedLerp(first.frame, middle.frame, last.frame, first.values, last.values);
-            if (computedMiddleValue.IsEqualTo(middle.values))
-            {
-                keys.RemoveAt(ixFirst + 1);
-                return true;
-            }
-            return false;
-
-        }
-
-        private static void ExportAnimation(string property, List<BabylonAnimation> animations, Func<int, float[]> extractValueFunc, BabylonAnimation.DataType dataType)
-        {
-            var exportNonOptimizedAnimations = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportnonoptimizedanimations");
-
-            var start = Loader.Core.AnimRange.Start;
-            var end = Loader.Core.AnimRange.End;
-
-            float[] previous = null;
-            var keys = new List<BabylonAnimationKey>();
-            for (var key = start; key <= end; key += Ticks)
-            {
-                var current = extractValueFunc(key);
-
-                if (exportNonOptimizedAnimations && previous != null && previous.IsEqualTo(current))
-                {
-                    continue; // Do not add key
-                }
-
-                keys.Add(new BabylonAnimationKey()
-                {
-                    frame = key / Ticks,
-                    values = current
-                });
-
-                previous = current;
-            }
-
-            if (!exportNonOptimizedAnimations)
-            {
-                RemoveLinearAnimationKeys(keys);
-            }
-
-            if (keys.Count > 1)
-            {
-                var animationPresent = true;
-
-                if (keys.Count == 2)
-                {
-                    if (keys[0].values.IsEqualTo(keys[1].values))
-                    {
-                        animationPresent = false;
-                    }
-                }
-
-                if (animationPresent)
-                {
-
-                    if (keys[keys.Count - 1].frame != end / Ticks)
-                    {
-                        keys.Add(new BabylonAnimationKey()
-                        {
-                            frame = end / Ticks,
-                            values = keys[keys.Count - 1].values
-                        });
-                    }
-
-                    var babylonAnimation = new BabylonAnimation
-                    {
-                        dataType = (int)dataType,
-                        name = property + " animation",
-                        keys = keys.ToArray(),
-                        framePerSecond = Loader.Global.FrameRate,
-                        loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle,
-                        property = property
-                    };
-
-                    animations.Add(babylonAnimation);
-                }
-            }
-        }
-    }
-}
+using System;
+using System.Collections.Generic;
+using Autodesk.Max;
+using BabylonExport.Entities;
+
+namespace Max2Babylon
+{
+    partial class BabylonExporter
+    {
+        const int Ticks = 160;
+
+        private static BabylonAnimationKey GenerateFloatFunc(int index, IIKeyControl keyControl)
+        {
+            var key = Loader.Global.ILinFloatKey.Create();
+            keyControl.GetKey(index, key);
+
+            return new BabylonAnimationKey
+            {
+                frame = key.Time / Ticks,
+                values = new[] { key.Val }
+            };
+        }
+
+        private static bool ExportFloatController(IControl control, string property, List<BabylonAnimation> animations)
+        {
+            return ExportController(control, property, animations, 0x2001, BabylonAnimation.DataType.Float, GenerateFloatFunc);
+        }
+
+        private static bool ExportQuaternionController(IControl control, string property, List<BabylonAnimation> animations)
+        {
+            IQuat previousQuat = null;
+
+            return ExportController(control, property, animations, 0x2003, BabylonAnimation.DataType.Quaternion,
+                (index, keyControl) =>
+                {
+                    var key = Loader.Global.ILinRotKey.Create();
+                    keyControl.GetKey(index, key);
+                    var newQuat = key.Val;
+
+                    if (index > 0)
+                    {
+                        newQuat = previousQuat.Multiply(newQuat);
+                    }
+
+                    previousQuat = newQuat;
+
+                    return new BabylonAnimationKey
+                    {
+                        frame = key.Time / Ticks,
+                        values = newQuat.ToArray()
+                    };
+                });
+        }
+
+        private static bool ExportVector3Controller(IControl control, string property, List<BabylonAnimation> animations)
+        {
+            var result = false;
+
+            if (control == null)
+            {
+                return false;
+            }
+
+            if (control.XController != null || control.YController != null || control.ZController != null)
+            {
+                result |= ExportFloatController(control.XController, property + ".x", animations);
+                result |= ExportFloatController(control.ZController, property + ".y", animations);
+                result |= ExportFloatController(control.YController, property + ".z", animations);
+
+                return result;
+            }
+
+            if (ExportController(control, property, animations, 0x2002, BabylonAnimation.DataType.Vector3,
+                (index, keyControl) =>
+                {
+                    var key = Loader.Global.ILinPoint3Key.Create();
+                    keyControl.GetKey(index, key);
+
+                    return new BabylonAnimationKey
+                    {
+                        frame = key.Time / Ticks,
+                        values = key.Val.ToArraySwitched()
+                    };
+                }))
+            {
+                return true;
+            }
+
+            return ExportController(control, property, animations, 0x2004, BabylonAnimation.DataType.Vector3,
+                (index, keyControl) =>
+                {
+                    var key = Loader.Global.ILinScaleKey.Create();
+                    keyControl.GetKey(index, key);
+
+                    return new BabylonAnimationKey
+                    {
+                        frame = key.Time / Ticks,
+                        values = key.Val.S.ToArraySwitched()
+                    };
+                });
+        }
+
+        private static bool ExportController(IControl control, string property, List<BabylonAnimation> animations, uint classId, BabylonAnimation.DataType dataType, Func<int, IIKeyControl, BabylonAnimationKey> generateFunc)
+        {
+            if (control == null)
+            {
+                return false;
+            }
+
+            var keyControl = control.GetInterface(InterfaceID.Keycontrol) as IIKeyControl;
+
+            if (keyControl == null)
+            {
+                return false;
+            }
+
+            if (control.ClassID.PartA != classId)
+            {
+                return false;
+            }
+
+            var keys = new List<BabylonAnimationKey>();
+            BabylonAnimation.LoopBehavior loopBehavior;
+
+            switch (control.GetORT(2))
+            {
+                case 2:
+                    loopBehavior = BabylonAnimation.LoopBehavior.Cycle;
+                    break;
+                default:
+                    loopBehavior = BabylonAnimation.LoopBehavior.Relative;
+                    break;
+            }
+
+            for (var index = 0; index < keyControl.NumKeys; index++)
+            {
+                keys.Add(generateFunc(index, keyControl));
+            }
+
+            if (keys.Count == 0)
+            {
+                return false;
+            }
+
+            var end = Loader.Core.AnimRange.End;
+            if (keys[keys.Count - 1].frame != end / Ticks)
+            {
+                keys.Add(new BabylonAnimationKey()
+                {
+                    frame = end / Ticks,
+                    values = keys[keys.Count - 1].values
+                });
+            }
+
+            var babylonAnimation = new BabylonAnimation
+            {
+                dataType = (int)dataType,
+                name = property + " animation",
+                keys = keys.ToArray(),
+                framePerSecond = Loader.Global.FrameRate,
+                loopBehavior = (int)loopBehavior,
+                property = property
+            };
+
+            animations.Add(babylonAnimation);
+
+            return true;
+        }
+
+        private static void ExportColor3Animation(string property, List<BabylonAnimation> animations,
+            Func<int, float[]> extractValueFunc)
+        {
+            ExportAnimation(property, animations, extractValueFunc, BabylonAnimation.DataType.Color3);
+        }
+
+        private static void ExportVector3Animation(string property, List<BabylonAnimation> animations,
+            Func<int, float[]> extractValueFunc)
+        {
+            ExportAnimation(property, animations, extractValueFunc, BabylonAnimation.DataType.Vector3);
+        }
+
+        private static void ExportQuaternionAnimation(string property, List<BabylonAnimation> animations,
+            Func<int, float[]> extractValueFunc)
+        {
+            ExportAnimation(property, animations, extractValueFunc, BabylonAnimation.DataType.Quaternion);
+        }
+
+        private static void ExportFloatAnimation(string property, List<BabylonAnimation> animations,
+            Func<int, float[]> extractValueFunc)
+        {
+            ExportAnimation(property, animations, extractValueFunc, BabylonAnimation.DataType.Float);
+        }
+
+        static void RemoveLinearAnimationKeys(List<BabylonAnimationKey> keys)
+        {
+            for (int ixFirst = keys.Count - 3; ixFirst >= 0; --ixFirst)
+            {
+                while (keys.Count - ixFirst >= 3)
+                {
+                    if (!RemoveAnimationKey(keys, ixFirst))
+                    {
+                        break;
+                    }
+                }
+            }
+        }
+
+        static float[] weightedLerp(int frame0, int frame1, int frame2, float[] value0, float[] value2)
+        {
+            double weight2 = (frame1 - frame0) / (double)(frame2 - frame0);
+            double weight0 = 1 - weight2;
+            float[] result = new float[value0.Length];
+            for (int i = 0; i < result.Length; ++i)
+            {
+                result[i] = (float)(value0[i] * weight0 + value2[i] * weight2);
+            }
+            return result;
+        }
+
+        private static bool RemoveAnimationKey(List<BabylonAnimationKey> keys, int ixFirst)
+        {
+            var first = keys[ixFirst];
+            var middle = keys[ixFirst + 1];
+            var last = keys[ixFirst + 2];
+
+            // first pass, frame equality
+            if (first.values.IsEqualTo(last.values) && first.values.IsEqualTo(middle.values))
+            {
+                keys.RemoveAt(ixFirst + 1);
+                return true;
+            }
+
+            // second pass : linear interpolation detection
+            var computedMiddleValue = weightedLerp(first.frame, middle.frame, last.frame, first.values, last.values);
+            if (computedMiddleValue.IsEqualTo(middle.values))
+            {
+                keys.RemoveAt(ixFirst + 1);
+                return true;
+            }
+            return false;
+
+        }
+
+        private static void ExportAnimation(string property, List<BabylonAnimation> animations, Func<int, float[]> extractValueFunc, BabylonAnimation.DataType dataType)
+        {
+            var exportNonOptimizedAnimations = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportnonoptimizedanimations");
+
+            var start = Loader.Core.AnimRange.Start;
+            var end = Loader.Core.AnimRange.End;
+
+            float[] previous = null;
+            var keys = new List<BabylonAnimationKey>();
+            for (var key = start; key <= end; key += Ticks)
+            {
+                var current = extractValueFunc(key);
+
+                if (exportNonOptimizedAnimations && previous != null && previous.IsEqualTo(current))
+                {
+                    continue; // Do not add key
+                }
+
+                keys.Add(new BabylonAnimationKey()
+                {
+                    frame = key / Ticks,
+                    values = current
+                });
+
+                previous = current;
+            }
+
+            if (!exportNonOptimizedAnimations)
+            {
+                RemoveLinearAnimationKeys(keys);
+            }
+
+            if (keys.Count > 1)
+            {
+                var animationPresent = true;
+
+                if (keys.Count == 2)
+                {
+                    if (keys[0].values.IsEqualTo(keys[1].values))
+                    {
+                        animationPresent = false;
+                    }
+                }
+
+                if (animationPresent)
+                {
+
+                    if (keys[keys.Count - 1].frame != end / Ticks)
+                    {
+                        keys.Add(new BabylonAnimationKey()
+                        {
+                            frame = end / Ticks,
+                            values = keys[keys.Count - 1].values
+                        });
+                    }
+
+                    var babylonAnimation = new BabylonAnimation
+                    {
+                        dataType = (int)dataType,
+                        name = property + " animation",
+                        keys = keys.ToArray(),
+                        framePerSecond = Loader.Global.FrameRate,
+                        loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle,
+                        property = property
+                    };
+
+                    animations.Add(babylonAnimation);
+                }
+            }
+        }
+    }
+}

+ 127 - 127
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Camera.cs

@@ -1,127 +1,127 @@
-using System.Collections.Generic;
-using Autodesk.Max;
-using BabylonExport.Entities;
-using System.Linq;
-
-namespace Max2Babylon
-{
-    partial class BabylonExporter
-    {
-        private void ExportCamera(IIGameScene scene,  IIGameNode cameraNode, BabylonScene babylonScene)
-        {
-            if (cameraNode.MaxNode.GetBoolProperty("babylonjs_noexport"))
-            {
-                return;
-            }
-            var gameCamera = cameraNode.IGameObject.AsGameCamera();
-            var maxCamera = gameCamera.MaxObject as ICameraObject;
-            var initialized = gameCamera.InitializeData;
-            var babylonCamera = new BabylonCamera();
-
-            RaiseMessage(cameraNode.Name, 1);
-            babylonCamera.name = cameraNode.Name;
-            babylonCamera.id = cameraNode.MaxNode.GetGuid().ToString();
-            if (cameraNode.NodeParent != null)
-            {
-                babylonCamera.parentId = GetParentID(cameraNode.NodeParent, babylonScene, scene);
-            }
-
-            babylonCamera.fov = Tools.ConvertFov(maxCamera.GetFOV(0, Tools.Forever));
-
-            if (maxCamera.ManualClip == 1)
-            {
-                babylonCamera.minZ = maxCamera.GetClipDist(0, 1, Tools.Forever);
-                babylonCamera.maxZ = maxCamera.GetClipDist(0, 2, Tools.Forever);
-            }
-            else
-            {
-                babylonCamera.minZ = 0.1f;
-                babylonCamera.maxZ = 10000.0f;
-            }
-
-            if (babylonCamera.minZ == 0.0f)
-            {
-                babylonCamera.minZ = 0.1f;
-            }
-
-            // Type
-            babylonCamera.type = cameraNode.MaxNode.GetStringProperty("babylonjs_type", "FreeCamera");
-
-            // Control
-            babylonCamera.speed = cameraNode.MaxNode.GetFloatProperty("babylonjs_speed", 1.0f);
-            babylonCamera.inertia = cameraNode.MaxNode.GetFloatProperty("babylonjs_inertia", 0.9f);
-
-            // Collisions
-            babylonCamera.checkCollisions = cameraNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions");
-            babylonCamera.applyGravity = cameraNode.MaxNode.GetBoolProperty("babylonjs_applygravity");
-            babylonCamera.ellipsoid = cameraNode.MaxNode.GetVector3Property("babylonjs_ellipsoid");
-
-            // Position
-            var wm = cameraNode.GetLocalTM(0);
-            if (cameraNode.NodeParent != null)
-            {
-                var parentWorld = cameraNode.NodeParent.GetObjectTM(0);
-                wm.MultiplyBy(parentWorld.Inverse);
-            }
-            var position = wm.Translation;
-            babylonCamera.position = new float[] { position.X, position.Y, position.Z };
-
-            // Target
-            var target = gameCamera.CameraTarget;
-            if (target != null)
-            {
-                babylonCamera.lockedTargetId = target.MaxNode.GetGuid().ToString();
-            }
-            else
-            {
-                var dir = wm.GetRow(3);
-                babylonCamera.target = new float[] { position.X - dir.X, position.Y - dir.Y, position.Z - dir.Z };
-            }
-
-            // Animations
-            var animations = new List<BabylonAnimation>();
-
-            ExportVector3Animation("position", animations, key =>
-            {
-                var tm = cameraNode.GetLocalTM(key);
-                if (cameraNode.NodeParent != null)
-                {
-                    var parentWorld = cameraNode.NodeParent.GetObjectTM(key);
-                    tm.MultiplyBy(parentWorld.Inverse);
-                }
-                var translation = tm.Translation;
-                return new float[] { translation.X, translation.Y, translation.Z };
-            });
-
-            if (gameCamera.CameraTarget == null)
-            {
-                ExportVector3Animation("target", animations, key =>
-                {
-                    var tm = cameraNode.GetLocalTM(key);
-                    if (cameraNode.NodeParent != null)
-                    {
-                        var parentWorld = cameraNode.NodeParent.GetObjectTM(key);
-                        tm.MultiplyBy(parentWorld.Inverse);
-                    }
-                    var translation = tm.Translation;
-                    var dir = tm.GetRow(3);
-                    return new float[] { translation.X - dir.X, translation.Y - dir.Y, translation.Z - dir.Z };
-                });
-            }
-
-            ExportFloatAnimation("fov", animations, key => new[] { Tools.ConvertFov((gameCamera.MaxObject as ICameraObject).GetFOV(key, Tools.Forever)) });
-
-            babylonCamera.animations = animations.ToArray();
-
-            if (cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimate"))
-            {
-                babylonCamera.autoAnimate = true;
-                babylonCamera.autoAnimateFrom = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from");
-                babylonCamera.autoAnimateTo = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to");
-                babylonCamera.autoAnimateLoop = cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop");
-            }
-
-            babylonScene.CamerasList.Add(babylonCamera);
-        }
-    }
-}
+using System.Collections.Generic;
+using Autodesk.Max;
+using BabylonExport.Entities;
+using System.Linq;
+
+namespace Max2Babylon
+{
+    partial class BabylonExporter
+    {
+        private void ExportCamera(IIGameScene scene,  IIGameNode cameraNode, BabylonScene babylonScene)
+        {
+            if (cameraNode.MaxNode.GetBoolProperty("babylonjs_noexport"))
+            {
+                return;
+            }
+            var gameCamera = cameraNode.IGameObject.AsGameCamera();
+            var maxCamera = gameCamera.MaxObject as ICameraObject;
+            var initialized = gameCamera.InitializeData;
+            var babylonCamera = new BabylonCamera();
+
+            RaiseMessage(cameraNode.Name, 1);
+            babylonCamera.name = cameraNode.Name;
+            babylonCamera.id = cameraNode.MaxNode.GetGuid().ToString();
+            if (cameraNode.NodeParent != null)
+            {
+                babylonCamera.parentId = GetParentID(cameraNode.NodeParent, babylonScene, scene);
+            }
+
+            babylonCamera.fov = Tools.ConvertFov(maxCamera.GetFOV(0, Tools.Forever));
+
+            if (maxCamera.ManualClip == 1)
+            {
+                babylonCamera.minZ = maxCamera.GetClipDist(0, 1, Tools.Forever);
+                babylonCamera.maxZ = maxCamera.GetClipDist(0, 2, Tools.Forever);
+            }
+            else
+            {
+                babylonCamera.minZ = 0.1f;
+                babylonCamera.maxZ = 10000.0f;
+            }
+
+            if (babylonCamera.minZ == 0.0f)
+            {
+                babylonCamera.minZ = 0.1f;
+            }
+
+            // Type
+            babylonCamera.type = cameraNode.MaxNode.GetStringProperty("babylonjs_type", "FreeCamera");
+
+            // Control
+            babylonCamera.speed = cameraNode.MaxNode.GetFloatProperty("babylonjs_speed", 1.0f);
+            babylonCamera.inertia = cameraNode.MaxNode.GetFloatProperty("babylonjs_inertia", 0.9f);
+
+            // Collisions
+            babylonCamera.checkCollisions = cameraNode.MaxNode.GetBoolProperty("babylonjs_checkcollisions");
+            babylonCamera.applyGravity = cameraNode.MaxNode.GetBoolProperty("babylonjs_applygravity");
+            babylonCamera.ellipsoid = cameraNode.MaxNode.GetVector3Property("babylonjs_ellipsoid");
+
+            // Position
+            var wm = cameraNode.GetLocalTM(0);
+            if (cameraNode.NodeParent != null)
+            {
+                var parentWorld = cameraNode.NodeParent.GetObjectTM(0);
+                wm.MultiplyBy(parentWorld.Inverse);
+            }
+            var position = wm.Translation;
+            babylonCamera.position = new [] { position.X, position.Y, position.Z };
+
+            // Target
+            var target = gameCamera.CameraTarget;
+            if (target != null)
+            {
+                babylonCamera.lockedTargetId = target.MaxNode.GetGuid().ToString();
+            }
+            else
+            {
+                var dir = wm.GetRow(3);
+                babylonCamera.target = new [] { position.X - dir.X, position.Y - dir.Y, position.Z - dir.Z };
+            }
+
+            // Animations
+            var animations = new List<BabylonAnimation>();
+
+            ExportVector3Animation("position", animations, key =>
+            {
+                var tm = cameraNode.GetLocalTM(key);
+                if (cameraNode.NodeParent != null)
+                {
+                    var parentWorld = cameraNode.NodeParent.GetObjectTM(key);
+                    tm.MultiplyBy(parentWorld.Inverse);
+                }
+                var translation = tm.Translation;
+                return new [] { translation.X, translation.Y, translation.Z };
+            });
+
+            if (gameCamera.CameraTarget == null)
+            {
+                ExportVector3Animation("target", animations, key =>
+                {
+                    var tm = cameraNode.GetLocalTM(key);
+                    if (cameraNode.NodeParent != null)
+                    {
+                        var parentWorld = cameraNode.NodeParent.GetObjectTM(key);
+                        tm.MultiplyBy(parentWorld.Inverse);
+                    }
+                    var translation = tm.Translation;
+                    var dir = tm.GetRow(3);
+                    return new float[] { translation.X - dir.X, translation.Y - dir.Y, translation.Z - dir.Z };
+                });
+            }
+
+            ExportFloatAnimation("fov", animations, key => new[] { Tools.ConvertFov((gameCamera.MaxObject as ICameraObject).GetFOV(key, Tools.Forever)) });
+
+            babylonCamera.animations = animations.ToArray();
+
+            if (cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimate"))
+            {
+                babylonCamera.autoAnimate = true;
+                babylonCamera.autoAnimateFrom = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from");
+                babylonCamera.autoAnimateTo = (int)cameraNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to");
+                babylonCamera.autoAnimateLoop = cameraNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop");
+            }
+
+            babylonScene.CamerasList.Add(babylonCamera);
+        }
+    }
+}

+ 227 - 218
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Light.cs

@@ -1,218 +1,227 @@
-using System;
-using System.Collections.Generic;
-using Autodesk.Max;
-using BabylonExport.Entities;
-using System.Linq;
-
-namespace Max2Babylon
-{
-    partial class BabylonExporter
-    {
-        void ExportDefaultLight(BabylonScene babylonScene)
-        {
-            var babylonLight = new BabylonLight();
-            babylonLight.name = "Default light";
-            babylonLight.id = Guid.NewGuid().ToString();
-            babylonLight.type = 3;
-            babylonLight.groundColor = new float[] { 0, 0, 0 };
-            babylonLight.direction = new[] { 0, 1.0f, 0 };
-
-            babylonLight.intensity = 1;
-
-            babylonLight.diffuse = new[] { 1.0f, 1.0f, 1.0f };
-            babylonLight.specular = new[] { 1.0f, 1.0f, 1.0f };
-
-            babylonScene.LightsList.Add(babylonLight);
-        }
-
-        private void ExportLight(IIGameScene scene, IIGameNode lightNode, BabylonScene babylonScene)
-        {
-            if (lightNode.MaxNode.GetBoolProperty("babylonjs_noexport"))
-            {
-                return;
-            }
-
-            var gameLight = lightNode.IGameObject.AsGameLight();
-            var initialized = gameLight.InitializeData;
-            var babylonLight = new BabylonLight();
-
-            RaiseMessage(lightNode.Name, 1);
-            babylonLight.name = lightNode.Name;
-            babylonLight.id = lightNode.MaxNode.GetGuid().ToString();
-            if (lightNode.NodeParent != null)
-            {
-                babylonLight.parentId = GetParentID(lightNode.NodeParent, babylonScene, scene);
-            }
-
-            // Type
-
-            var maxLight = (lightNode.MaxNode.ObjectRef as ILightObject);
-            var lightState = Loader.Global.LightState.Create();
-            maxLight.EvalLightState(0, Tools.Forever, lightState);
-
-            switch (lightState.Type)
-            {
-                case LightType.OmniLgt:
-                    babylonLight.type = 0;
-                    break;
-                case LightType.SpotLgt:
-                    babylonLight.type = 2;
-                    babylonLight.angle = (float)(maxLight.GetFallsize(0, Tools.Forever) * Math.PI / 180.0f);
-                    babylonLight.exponent = 1;
-                    break;
-                case LightType.DirectLgt:
-                    babylonLight.type = 1;
-                    break;
-                case LightType.AmbientLgt:
-                    babylonLight.type = 3;
-                    babylonLight.groundColor = new float[] { 0, 0, 0 };
-                    break;
-            }
-
-
-            // Shadows 
-            if (maxLight.ShadowMethod == 1)
-            {
-                if (lightState.Type == LightType.DirectLgt || lightState.Type == LightType.SpotLgt)
-                {
-                    ExportShadowGenerator(lightNode.MaxNode, babylonScene);
-                }
-                else
-                {
-                    RaiseWarning("Shadows maps are only supported for directional and spot lights", 2);
-                }
-            }
-
-            // Position
-            var wm = lightNode.GetObjectTM(0);
-            if (lightNode.NodeParent != null)
-            {
-                var parentWorld = lightNode.NodeParent.GetObjectTM(0);
-                wm.MultiplyBy(parentWorld.Inverse);
-            }
-            var position = wm.Translation;
-            babylonLight.position = new[] { position.X, position.Y, position.Z };
-
-            // Direction
-            var target = gameLight.LightTarget;
-            if (target != null)
-            {
-                var targetWm = target.GetObjectTM(0);
-                var targetPosition = targetWm.Translation;
-
-                var direction = targetPosition.Subtract(position).Normalize;
-                babylonLight.direction = new[] { direction.X, direction.Y, direction.Z };
-            }
-            else
-            {
-                var vDir = Loader.Global.Point3.Create(0, -1, 0);
-                vDir = wm.ExtractMatrix3().VectorTransform(vDir).Normalize;
-                babylonLight.direction = new[] { vDir.X, vDir.Y, vDir.Z };
-            }
-
-            var maxScene = Loader.Core.RootNode;
-
-            // Exclusion
-            var inclusion = maxLight.ExclList.TestFlag(1); //NT_INCLUDE 
-            var checkExclusionList = maxLight.ExclList.TestFlag(2); //NT_AFFECT_ILLUM
-
-            if (checkExclusionList)
-            {
-                var excllist = new List<string>();
-                var incllist = new List<string>();
-
-                foreach (var meshNode in maxScene.NodesListBySuperClass(SClass_ID.Geomobject))
-                {
-                    if (meshNode.CastShadows == 1)
-                    {
-                        var inList = maxLight.ExclList.FindNode(meshNode) != -1;
-
-                        if (inList)
-                        {
-                            if (inclusion)
-                            {
-                                incllist.Add(meshNode.GetGuid().ToString());
-                            }
-                            else
-                            {
-                                excllist.Add(meshNode.GetGuid().ToString());
-                            }
-                        }
-                    }
-                }
-
-                babylonLight.includedOnlyMeshesIds = incllist.ToArray();
-                babylonLight.excludedMeshesIds = excllist.ToArray();
-            }
-
-            // Other fields 
-            babylonLight.intensity = maxLight.GetIntensity(0, Tools.Forever);
-
-
-            babylonLight.diffuse = lightState.AffectDiffuse ? maxLight.GetRGBColor(0, Tools.Forever).ToArray() : new float[] { 0, 0, 0 };
-            babylonLight.specular = lightState.AffectDiffuse ? maxLight.GetRGBColor(0, Tools.Forever).ToArray() : new float[] { 0, 0, 0 };
-
-
-            if (maxLight.UseAtten)
-            {
-                babylonLight.range = maxLight.GetAtten(0, 1, Tools.Forever);
-            }
-
-
-            // Animations
-            var animations = new List<BabylonAnimation>();
-
-            ExportVector3Animation("position", animations, key =>
-            {
-                var mat = lightNode.GetObjectTM(key);
-                if (lightNode.NodeParent != null)
-                {
-                    var parentWorld = lightNode.NodeParent.GetObjectTM(key);
-                    mat.MultiplyBy(parentWorld.Inverse);
-                }
-                var pos = mat.Translation;
-                return new[] { pos.X, pos.Y, pos.Z };
-            });
-
-            ExportVector3Animation("direction", animations, key =>
-            {
-                var wmLight = lightNode.GetObjectTM(key);
-                if (lightNode.NodeParent != null)
-                {
-                    var parentWorld = lightNode.NodeParent.GetObjectTM(key);
-                    wmLight.MultiplyBy(parentWorld.Inverse);
-                }
-                var positionLight = wmLight.Translation;
-                var lightTarget = gameLight.LightTarget;
-                if (lightTarget != null)
-                {
-                    var targetWm = lightTarget.GetObjectTM(key);
-                    var targetPosition = targetWm.Translation;
-
-                    var direction = targetPosition.Subtract(positionLight).Normalize;
-                    return new[] { direction.X, direction.Y, direction.Z };
-                }
-                else
-                {
-                    var vDir = Loader.Global.Point3.Create(0, -1, 0);
-                    vDir = wmLight.ExtractMatrix3().VectorTransform(vDir).Normalize;
-                    return new[] { vDir.X, vDir.Y, vDir.Z };
-                }
-            });
-
-            ExportFloatAnimation("intensity", animations, key => new[] { maxLight.GetIntensity(key, Tools.Forever) });
-
-            babylonLight.animations = animations.ToArray();
-
-            if (lightNode.MaxNode.GetBoolProperty("babylonjs_autoanimate"))
-            {
-                babylonLight.autoAnimate = true;
-                babylonLight.autoAnimateFrom = (int)lightNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from");
-                babylonLight.autoAnimateTo = (int)lightNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to");
-                babylonLight.autoAnimateLoop = lightNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop");
-            }
-
-            babylonScene.LightsList.Add(babylonLight);
-        }
-    }
-}
+using System;
+using System.Collections.Generic;
+using Autodesk.Max;
+using BabylonExport.Entities;
+using System.Linq;
+
+namespace Max2Babylon
+{
+    partial class BabylonExporter
+    {
+        void ExportDefaultLight(BabylonScene babylonScene)
+        {
+            var babylonLight = new BabylonLight();
+            babylonLight.name = "Default light";
+            babylonLight.id = Guid.NewGuid().ToString();
+            babylonLight.type = 3;
+            babylonLight.groundColor = new float[] { 0, 0, 0 };
+            babylonLight.direction = new[] { 0, 1.0f, 0 };
+
+            babylonLight.intensity = 1;
+
+            babylonLight.diffuse = new[] { 1.0f, 1.0f, 1.0f };
+            babylonLight.specular = new[] { 1.0f, 1.0f, 1.0f };
+
+            babylonScene.LightsList.Add(babylonLight);
+        }
+
+        private void ExportLight(IIGameScene scene, IIGameNode lightNode, BabylonScene babylonScene)
+        {
+            if (lightNode.MaxNode.GetBoolProperty("babylonjs_noexport"))
+            {
+                return;
+            }
+
+            var gameLight = lightNode.IGameObject.AsGameLight();
+            var initialized = gameLight.InitializeData;
+            var babylonLight = new BabylonLight();
+
+            RaiseMessage(lightNode.Name, 1);
+            babylonLight.name = lightNode.Name;
+            babylonLight.id = lightNode.MaxNode.GetGuid().ToString();
+            if (lightNode.NodeParent != null)
+            {
+                babylonLight.parentId = GetParentID(lightNode.NodeParent, babylonScene, scene);
+            }
+
+            // Type
+
+            var maxLight = (lightNode.MaxNode.ObjectRef as ILightObject);
+            var lightState = Loader.Global.LightState.Create();
+            maxLight.EvalLightState(0, Tools.Forever, lightState);
+
+            switch (lightState.Type)
+            {
+                case LightType.OmniLgt:
+                    babylonLight.type = 0;
+                    break;
+                case LightType.SpotLgt:
+                    babylonLight.type = 2;
+                    babylonLight.angle = (float)(maxLight.GetFallsize(0, Tools.Forever) * Math.PI / 180.0f);
+                    babylonLight.exponent = 1;
+                    break;
+                case LightType.DirectLgt:
+                    babylonLight.type = 1;
+                    break;
+                case LightType.AmbientLgt:
+                    babylonLight.type = 3;
+                    babylonLight.groundColor = new float[] { 0, 0, 0 };
+                    break;
+            }
+
+
+            // Shadows 
+            if (maxLight.ShadowMethod == 1)
+            {
+                if (lightState.Type == LightType.DirectLgt || lightState.Type == LightType.SpotLgt || lightState.Type == LightType.OmniLgt)
+                {
+                    ExportShadowGenerator(lightNode.MaxNode, babylonScene);
+                }
+                else
+                {
+                    RaiseWarning("Shadows maps are only supported for point, directional and spot lights", 2);
+                }
+            }
+
+            // Position
+            var wm = lightNode.GetObjectTM(0);
+            if (lightNode.NodeParent != null)
+            {
+                var parentWorld = lightNode.NodeParent.GetObjectTM(0);
+                wm.MultiplyBy(parentWorld.Inverse);
+            }
+            var position = wm.Translation;
+            babylonLight.position = new[] { position.X, position.Y, position.Z };
+
+            // Direction
+            var target = gameLight.LightTarget;
+            if (target != null)
+            {
+                var targetWm = target.GetObjectTM(0);
+                var targetPosition = targetWm.Translation;
+
+                var direction = targetPosition.Subtract(position).Normalize;
+                babylonLight.direction = new[] { direction.X, direction.Y, direction.Z };
+            }
+            else
+            {
+                var vDir = Loader.Global.Point3.Create(0, -1, 0);
+                vDir = wm.ExtractMatrix3().VectorTransform(vDir).Normalize;
+                babylonLight.direction = new[] { vDir.X, vDir.Y, vDir.Z };
+            }
+
+            var maxScene = Loader.Core.RootNode;
+
+            // Exclusion
+            var inclusion = maxLight.ExclList.TestFlag(1); //NT_INCLUDE 
+            var checkExclusionList = maxLight.ExclList.TestFlag(2); //NT_AFFECT_ILLUM
+
+            if (checkExclusionList)
+            {
+                var excllist = new List<string>();
+                var incllist = new List<string>();
+
+                foreach (var meshNode in maxScene.NodesListBySuperClass(SClass_ID.Geomobject))
+                {
+#if MAX2017
+                    if (meshNode.CastShadows)
+#else
+                    if (meshNode.CastShadows == 1)
+#endif
+                    {
+                        var inList = maxLight.ExclList.FindNode(meshNode) != -1;
+
+                        if (inList)
+                        {
+                            if (inclusion)
+                            {
+                                incllist.Add(meshNode.GetGuid().ToString());
+                            }
+                            else
+                            {
+                                excllist.Add(meshNode.GetGuid().ToString());
+                            }
+                        }
+                    }
+                }
+
+                babylonLight.includedOnlyMeshesIds = incllist.ToArray();
+                babylonLight.excludedMeshesIds = excllist.ToArray();
+            }
+
+            // Other fields 
+            babylonLight.intensity = maxLight.GetIntensity(0, Tools.Forever);
+
+
+            babylonLight.diffuse = lightState.AffectDiffuse ? maxLight.GetRGBColor(0, Tools.Forever).ToArray() : new float[] { 0, 0, 0 };
+            babylonLight.specular = lightState.AffectDiffuse ? maxLight.GetRGBColor(0, Tools.Forever).ToArray() : new float[] { 0, 0, 0 };
+
+
+            if (maxLight.UseAtten)
+            {
+                babylonLight.range = maxLight.GetAtten(0, 3, Tools.Forever);
+            }
+
+
+            // Animations
+            var animations = new List<BabylonAnimation>();
+
+            ExportVector3Animation("position", animations, key =>
+            {
+                var mat = lightNode.GetObjectTM(key);
+                if (lightNode.NodeParent != null)
+                {
+                    var parentWorld = lightNode.NodeParent.GetObjectTM(key);
+                    mat.MultiplyBy(parentWorld.Inverse);
+                }
+                var pos = mat.Translation;
+                return new[] { pos.X, pos.Y, pos.Z };
+            });
+
+            ExportVector3Animation("direction", animations, key =>
+            {
+                var wmLight = lightNode.GetObjectTM(key);
+                if (lightNode.NodeParent != null)
+                {
+                    var parentWorld = lightNode.NodeParent.GetObjectTM(key);
+                    wmLight.MultiplyBy(parentWorld.Inverse);
+                }
+                var positionLight = wmLight.Translation;
+                var lightTarget = gameLight.LightTarget;
+                if (lightTarget != null)
+                {
+                    var targetWm = lightTarget.GetObjectTM(key);
+                    var targetPosition = targetWm.Translation;
+
+                    var direction = targetPosition.Subtract(positionLight).Normalize;
+                    return new[] { direction.X, direction.Y, direction.Z };
+                }
+                else
+                {
+                    var vDir = Loader.Global.Point3.Create(0, -1, 0);
+                    vDir = wmLight.ExtractMatrix3().VectorTransform(vDir).Normalize;
+                    return new[] { vDir.X, vDir.Y, vDir.Z };
+                }
+            });
+
+            ExportFloatAnimation("intensity", animations, key => new[] { maxLight.GetIntensity(key, Tools.Forever) });
+
+            ExportColor3Animation("diffuse", animations, key =>
+            {
+                return lightState.AffectDiffuse? maxLight.GetRGBColor(key, Tools.Forever).ToArray() : new float[] { 0, 0, 0 };
+            });
+
+            babylonLight.animations = animations.ToArray();
+
+            if (lightNode.MaxNode.GetBoolProperty("babylonjs_autoanimate"))
+            {
+                babylonLight.autoAnimate = true;
+                babylonLight.autoAnimateFrom = (int)lightNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from");
+                babylonLight.autoAnimateTo = (int)lightNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to");
+                babylonLight.autoAnimateLoop = lightNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop");
+            }
+
+            babylonScene.LightsList.Add(babylonLight);
+        }
+    }
+}

+ 149 - 149
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Material.cs

@@ -1,149 +1,149 @@
-using System;
-using System.Collections.Generic;
-using Autodesk.Max;
-using BabylonExport.Entities;
-
-namespace Max2Babylon
-{
-    partial class BabylonExporter
-    {
-        readonly List<IIGameMaterial> referencedMaterials = new List<IIGameMaterial>();
-
-        private void ExportMaterial(IIGameMaterial materialNode, BabylonScene babylonScene)
-        {
-            var name = materialNode.MaterialName;
-            var id = materialNode.MaxMaterial.GetGuid().ToString();
-
-            RaiseMessage(name, 1);
-
-            if (materialNode.SubMaterialCount > 0)
-            {
-                var babylonMultimaterial = new BabylonMultiMaterial { name = name, id = id };
-
-                var guids = new List<string>();
-
-                for (var index = 0; index < materialNode.SubMaterialCount; index++)
-                {
-                    var subMat = materialNode.GetSubMaterial(index);
-
-                    if (subMat != null)
-                    {
-                        guids.Add(subMat.MaxMaterial.GetGuid().ToString());
-
-                        if (!referencedMaterials.Contains(subMat))
-                        {
-                            referencedMaterials.Add(subMat);
-                            ExportMaterial(subMat, babylonScene);
-                        }
-                    }
-                    else
-                    {
-                        guids.Add(Guid.Empty.ToString());
-                    }
-                }
-
-                babylonMultimaterial.materials = guids.ToArray();
-
-                babylonScene.MultiMaterialsList.Add(babylonMultimaterial);
-                return;
-            }
-
-            var babylonMaterial = new BabylonMaterial
-            {
-                name = name,
-                id = id,
-                ambient = materialNode.MaxMaterial.GetAmbient(0, false).ToArray(),
-                diffuse = materialNode.MaxMaterial.GetDiffuse(0, false).ToArray(),
-                specular = materialNode.MaxMaterial.GetSpecular(0, false).Scale(materialNode.MaxMaterial.GetShinStr(0, false)),
-                specularPower = materialNode.MaxMaterial.GetShininess(0, false) * 256,
-                emissive =
-                    materialNode.MaxMaterial.GetSelfIllumColorOn(0, false)
-                        ? materialNode.MaxMaterial.GetSelfIllumColor(0, false).ToArray()
-                        : materialNode.MaxMaterial.GetDiffuse(0, false).Scale(materialNode.MaxMaterial.GetSelfIllum(0, false)),
-                alpha = 1.0f - materialNode.MaxMaterial.GetXParency(0, false)
-            };
-
-
-            var stdMat = materialNode.MaxMaterial.GetParamBlock(0).Owner as IStdMat2;
-
-            if (stdMat != null)
-            {
-                babylonMaterial.backFaceCulling = !stdMat.TwoSided;
-                babylonMaterial.wireframe = stdMat.Wire;
-
-                // Textures
-                BabylonFresnelParameters fresnelParameters;
-
-                babylonMaterial.ambientTexture = ExportTexture(stdMat, 0, out fresnelParameters, babylonScene);                // Ambient
-                babylonMaterial.diffuseTexture = ExportTexture(stdMat, 1, out fresnelParameters, babylonScene);                // Diffuse
-                if (fresnelParameters != null)
-                {
-                    babylonMaterial.diffuseFresnelParameters = fresnelParameters;
-                }
-
-                babylonMaterial.specularTexture = ExportTexture(stdMat, 2, out fresnelParameters, babylonScene);               // Specular
-                babylonMaterial.emissiveTexture = ExportTexture(stdMat, 5, out fresnelParameters, babylonScene);               // Emissive
-                if (fresnelParameters != null)
-                {
-                    babylonMaterial.emissiveFresnelParameters = fresnelParameters;
-                    if (babylonMaterial.emissive[0] == 0 &&
-                        babylonMaterial.emissive[1] == 0 &&
-                        babylonMaterial.emissive[2] == 0 &&
-                        babylonMaterial.emissiveTexture == null)
-                    {
-                        babylonMaterial.emissive = new float[] { 1, 1, 1 };
-                    }
-                }
-
-                babylonMaterial.opacityTexture = ExportTexture(stdMat, 6, out fresnelParameters, babylonScene, false, true);   // Opacity
-                if (fresnelParameters != null)
-                {
-                    babylonMaterial.opacityFresnelParameters = fresnelParameters;
-                    if (babylonMaterial.alpha == 1 &&
-                         babylonMaterial.opacityTexture == null)
-                    {
-                        babylonMaterial.alpha = 0;
-                    }
-                }
-
-                babylonMaterial.bumpTexture = ExportTexture(stdMat, 8, out fresnelParameters, babylonScene);                   // Bump
-                babylonMaterial.reflectionTexture = ExportTexture(stdMat, 9, out fresnelParameters, babylonScene, true);       // Reflection
-                if (fresnelParameters != null)
-                {
-                    if (babylonMaterial.reflectionTexture == null)
-                    {
-                        RaiseWarning("Fallout cannot be used with reflection channel without a texture", 2);
-                    }
-                    else
-                    {
-                        babylonMaterial.reflectionFresnelParameters = fresnelParameters;
-                    }
-                }
-
-                // Constraints
-                if (babylonMaterial.diffuseTexture != null)
-                {
-                    babylonMaterial.diffuse = new[] { 1.0f, 1.0f, 1.0f };
-                }
-
-                if (babylonMaterial.emissiveTexture != null)
-                {
-                    babylonMaterial.emissive = new float[] { 0, 0, 0 };
-                }
-
-                if (babylonMaterial.opacityTexture != null && babylonMaterial.diffuseTexture != null &&
-                    babylonMaterial.diffuseTexture.name == babylonMaterial.opacityTexture.name &&
-                    babylonMaterial.diffuseTexture.hasAlpha && !babylonMaterial.opacityTexture.getAlphaFromRGB)
-                {
-                    // This is a alpha testing purpose
-                    babylonMaterial.opacityTexture = null;
-                    babylonMaterial.diffuseTexture.hasAlpha = true;
-                    RaiseWarning("Opacity texture was removed because alpha from diffuse texture can be use instead", 2);
-                    RaiseWarning("If you do not want this behavior, just set Alpha Source = None on your diffuse texture", 2);
-                }
-            }
-
-            babylonScene.MaterialsList.Add(babylonMaterial);
-        }
-    }
-}
+using System;
+using System.Collections.Generic;
+using Autodesk.Max;
+using BabylonExport.Entities;
+
+namespace Max2Babylon
+{
+    partial class BabylonExporter
+    {
+        readonly List<IIGameMaterial> referencedMaterials = new List<IIGameMaterial>();
+
+        private void ExportMaterial(IIGameMaterial materialNode, BabylonScene babylonScene)
+        {
+            var name = materialNode.MaterialName;
+            var id = materialNode.MaxMaterial.GetGuid().ToString();
+
+            RaiseMessage(name, 1);
+
+            if (materialNode.SubMaterialCount > 0)
+            {
+                var babylonMultimaterial = new BabylonMultiMaterial { name = name, id = id };
+
+                var guids = new List<string>();
+
+                for (var index = 0; index < materialNode.SubMaterialCount; index++)
+                {
+                    var subMat = materialNode.GetSubMaterial(index);
+
+                    if (subMat != null)
+                    {
+                        guids.Add(subMat.MaxMaterial.GetGuid().ToString());
+
+                        if (!referencedMaterials.Contains(subMat))
+                        {
+                            referencedMaterials.Add(subMat);
+                            ExportMaterial(subMat, babylonScene);
+                        }
+                    }
+                    else
+                    {
+                        guids.Add(Guid.Empty.ToString());
+                    }
+                }
+
+                babylonMultimaterial.materials = guids.ToArray();
+
+                babylonScene.MultiMaterialsList.Add(babylonMultimaterial);
+                return;
+            }
+
+            var babylonMaterial = new BabylonStandardMaterial
+            {
+                name = name,
+                id = id,
+                ambient = materialNode.MaxMaterial.GetAmbient(0, false).ToArray(),
+                diffuse = materialNode.MaxMaterial.GetDiffuse(0, false).ToArray(),
+                specular = materialNode.MaxMaterial.GetSpecular(0, false).Scale(materialNode.MaxMaterial.GetShinStr(0, false)),
+                specularPower = materialNode.MaxMaterial.GetShininess(0, false) * 256,
+                emissive =
+                    materialNode.MaxMaterial.GetSelfIllumColorOn(0, false)
+                        ? materialNode.MaxMaterial.GetSelfIllumColor(0, false).ToArray()
+                        : materialNode.MaxMaterial.GetDiffuse(0, false).Scale(materialNode.MaxMaterial.GetSelfIllum(0, false)),
+                alpha = 1.0f - materialNode.MaxMaterial.GetXParency(0, false)
+            };
+
+
+            var stdMat = materialNode.MaxMaterial.GetParamBlock(0).Owner as IStdMat2;
+
+            if (stdMat != null)
+            {
+                babylonMaterial.backFaceCulling = !stdMat.TwoSided;
+                babylonMaterial.wireframe = stdMat.Wire;
+
+                // Textures
+                BabylonFresnelParameters fresnelParameters;
+
+                babylonMaterial.ambientTexture = ExportTexture(stdMat, 0, out fresnelParameters, babylonScene);                // Ambient
+                babylonMaterial.diffuseTexture = ExportTexture(stdMat, 1, out fresnelParameters, babylonScene);                // Diffuse
+                if (fresnelParameters != null)
+                {
+                    babylonMaterial.diffuseFresnelParameters = fresnelParameters;
+                }
+
+                babylonMaterial.specularTexture = ExportTexture(stdMat, 2, out fresnelParameters, babylonScene);               // Specular
+                babylonMaterial.emissiveTexture = ExportTexture(stdMat, 5, out fresnelParameters, babylonScene);               // Emissive
+                if (fresnelParameters != null)
+                {
+                    babylonMaterial.emissiveFresnelParameters = fresnelParameters;
+                    if (babylonMaterial.emissive[0] == 0 &&
+                        babylonMaterial.emissive[1] == 0 &&
+                        babylonMaterial.emissive[2] == 0 &&
+                        babylonMaterial.emissiveTexture == null)
+                    {
+                        babylonMaterial.emissive = new float[] { 1, 1, 1 };
+                    }
+                }
+
+                babylonMaterial.opacityTexture = ExportTexture(stdMat, 6, out fresnelParameters, babylonScene, false, true);   // Opacity
+                if (fresnelParameters != null)
+                {
+                    babylonMaterial.opacityFresnelParameters = fresnelParameters;
+                    if (babylonMaterial.alpha == 1 &&
+                         babylonMaterial.opacityTexture == null)
+                    {
+                        babylonMaterial.alpha = 0;
+                    }
+                }
+
+                babylonMaterial.bumpTexture = ExportTexture(stdMat, 8, out fresnelParameters, babylonScene);                   // Bump
+                babylonMaterial.reflectionTexture = ExportTexture(stdMat, 9, out fresnelParameters, babylonScene, true);       // Reflection
+                if (fresnelParameters != null)
+                {
+                    if (babylonMaterial.reflectionTexture == null)
+                    {
+                        RaiseWarning("Fallout cannot be used with reflection channel without a texture", 2);
+                    }
+                    else
+                    {
+                        babylonMaterial.reflectionFresnelParameters = fresnelParameters;
+                    }
+                }
+
+                // Constraints
+                if (babylonMaterial.diffuseTexture != null)
+                {
+                    babylonMaterial.diffuse = new[] { 1.0f, 1.0f, 1.0f };
+                }
+
+                if (babylonMaterial.emissiveTexture != null)
+                {
+                    babylonMaterial.emissive = new float[] { 0, 0, 0 };
+                }
+
+                if (babylonMaterial.opacityTexture != null && babylonMaterial.diffuseTexture != null &&
+                    babylonMaterial.diffuseTexture.name == babylonMaterial.opacityTexture.name &&
+                    babylonMaterial.diffuseTexture.hasAlpha && !babylonMaterial.opacityTexture.getAlphaFromRGB)
+                {
+                    // This is a alpha testing purpose
+                    babylonMaterial.opacityTexture = null;
+                    babylonMaterial.diffuseTexture.hasAlpha = true;
+                    RaiseWarning("Opacity texture was removed because alpha from diffuse texture can be use instead", 2);
+                    RaiseWarning("If you do not want this behavior, just set Alpha Source = None on your diffuse texture", 2);
+                }
+            }
+
+            babylonScene.MaterialsList.Add(babylonMaterial);
+        }
+    }
+}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 798 - 726
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs


+ 70 - 65
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.ShadowGenerator.cs

@@ -1,65 +1,70 @@
-using System.Collections.Generic;
-using Autodesk.Max;
-using BabylonExport.Entities;
-
-namespace Max2Babylon
-{
-    partial class BabylonExporter
-    {
-        private BabylonShadowGenerator ExportShadowGenerator(IINode lightNode, BabylonScene babylonScene)
-        {
-            var maxLight = (lightNode.ObjectRef as ILightObject);
-            var babylonShadowGenerator = new BabylonShadowGenerator();
-
-            RaiseMessage("Exporting shadow map", 2);
-
-            babylonShadowGenerator.lightId = lightNode.GetGuid().ToString();
-
-            babylonShadowGenerator.mapSize = maxLight.GetMapSize(0, Tools.Forever);
-
-            babylonShadowGenerator.bias = lightNode.GetFloatProperty("babylonjs_shadows_bias", 0.00005f);
-
-            var shadowsType = lightNode.GetStringProperty("babylonjs_shadows_type", "Blurred Variance");
-
-            switch (shadowsType)
-            {
-                case "Hard shadows":
-                    break;
-                case "Poisson Sampling":
-                    babylonShadowGenerator.usePoissonSampling = true;
-                    break;
-                case "Variance":
-                    babylonShadowGenerator.useVarianceShadowMap = true;
-                    break;
-                case"Blurred Variance":
-                    babylonShadowGenerator.useBlurVarianceShadowMap = true;
-                    babylonShadowGenerator.blurScale = lightNode.GetFloatProperty("babylonjs_shadows_blurScale", 2);
-                    babylonShadowGenerator.blurBoxOffset = lightNode.GetFloatProperty("babylonjs_shadows_blurBoxOffset", 1);
-                    break;
-            }
-
-            
-            var list = new List<string>();
-
-            var inclusion = maxLight.ExclList.TestFlag(1); //NT_INCLUDE 
-            var checkExclusionList = maxLight.ExclList.TestFlag(4); //NT_AFFECT_SHADOWCAST 
-
-            foreach (var meshNode in Loader.Core.RootNode.NodesListBySuperClass(SClass_ID.Geomobject))
-            {
-                if (meshNode.CastShadows == 1)
-                {
-                    var inList = maxLight.ExclList.FindNode(meshNode) != -1;
-
-                    if (!checkExclusionList || (inList && inclusion) || (!inList && !inclusion))
-                    {
-                        list.Add(meshNode.GetGuid().ToString());
-                    }
-                }
-            }
-            babylonShadowGenerator.renderList = list.ToArray();
-
-            babylonScene.ShadowGeneratorsList.Add(babylonShadowGenerator);
-            return babylonShadowGenerator;
-        }
-    }
-}
+using System.Collections.Generic;
+using Autodesk.Max;
+using BabylonExport.Entities;
+
+namespace Max2Babylon
+{
+    partial class BabylonExporter
+    {
+        private BabylonShadowGenerator ExportShadowGenerator(IINode lightNode, BabylonScene babylonScene)
+        {
+            var maxLight = (lightNode.ObjectRef as ILightObject);
+            var babylonShadowGenerator = new BabylonShadowGenerator();
+
+            RaiseMessage("Exporting shadow map", 2);
+
+            babylonShadowGenerator.lightId = lightNode.GetGuid().ToString();
+
+            babylonShadowGenerator.mapSize = maxLight.GetMapSize(0, Tools.Forever);
+
+            babylonShadowGenerator.bias = lightNode.GetFloatProperty("babylonjs_shadows_bias", 0.00005f);
+            babylonShadowGenerator.forceBackFacesOnly = lightNode.GetBoolProperty("babylonjs_forcebackfaces");
+
+            var shadowsType = lightNode.GetStringProperty("babylonjs_shadows_type", "Blurred Variance");
+
+            switch (shadowsType)
+            {
+                case "Hard shadows":
+                    break;
+                case "Poisson Sampling":
+                    babylonShadowGenerator.usePoissonSampling = true;
+                    break;
+                case "Variance":
+                    babylonShadowGenerator.useVarianceShadowMap = true;
+                    break;
+                case"Blurred Variance":
+                    babylonShadowGenerator.useBlurVarianceShadowMap = true;
+                    babylonShadowGenerator.blurScale = lightNode.GetFloatProperty("babylonjs_shadows_blurScale", 2);
+                    babylonShadowGenerator.blurBoxOffset = lightNode.GetFloatProperty("babylonjs_shadows_blurBoxOffset", 1);
+                    break;
+            }
+
+            
+            var list = new List<string>();
+
+            var inclusion = maxLight.ExclList.TestFlag(1); //NT_INCLUDE 
+            var checkExclusionList = maxLight.ExclList.TestFlag(4); //NT_AFFECT_SHADOWCAST 
+
+            foreach (var meshNode in Loader.Core.RootNode.NodesListBySuperClass(SClass_ID.Geomobject))
+            {
+#if MAX2017
+                if (meshNode.CastShadows)
+#else
+                if (meshNode.CastShadows == 1)
+#endif
+                {
+                    var inList = maxLight.ExclList.FindNode(meshNode) != -1;
+
+                    if (!checkExclusionList || (inList && inclusion) || (!inList && !inclusion))
+                    {
+                        list.Add(meshNode.GetGuid().ToString());
+                    }
+                }
+            }
+            babylonShadowGenerator.renderList = list.ToArray();
+
+            babylonScene.ShadowGeneratorsList.Add(babylonShadowGenerator);
+            return babylonShadowGenerator;
+        }
+    }
+}

+ 135 - 134
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Skeleton.cs

@@ -1,134 +1,135 @@
-using System;
-using System.Collections.Generic;
-using Autodesk.Max;
-using BabylonExport.Entities;
-using SharpDX;
-
-namespace Max2Babylon
-{
-    internal class BonePoseInfo
-    {
-        public IGMatrix AbsoluteTransform { get; set; }
-        public IGMatrix LocalTransform { get; set; }
-    }
-    partial class BabylonExporter
-    {
-        readonly List<IIGameSkin> skins = new List<IIGameSkin>();
-        readonly List<IIGameNode> skinnedNodes = new List<IIGameNode>();
-
-        IGMatrix WithNoScale(IGMatrix mat)
-        {
-            var mat3 = mat.ExtractMatrix3();
-            mat3.NoScale();
-            return Loader.Global.GMatrix.Create(mat3);
-        }
-        private void ExportSkin(IIGameSkin skin, BabylonScene babylonScene)
-        {
-            var babylonSkeleton = new BabylonSkeleton { id = skins.IndexOf(skin) };
-            babylonSkeleton.name = "skeleton #" + babylonSkeleton.id;
-
-            RaiseMessage(babylonSkeleton.name, 1);
-
-            var skinIndex = skins.IndexOf(skin);
-            var meshNode = skinnedNodes[skinIndex];
-            var skinInitMatrix = meshNode.GetObjectTM(0);
-
-            var bones = new List<BabylonBone>();
-            var gameBones = new List<IIGameNode>();
-            var boneIds = new List<int>();
-            var bindPoseInfos = new List<BonePoseInfo>();
-            for(int i = 0; i < skin.TotalSkinBoneCount; ++i)
-            {
-                bones.Add(null);
-                gameBones.Add(null);
-                boneIds.Add(-1);
-                bindPoseInfos.Add(null);
-            }
-            for (var index = 0; index < skin.TotalSkinBoneCount; index++)
-            {
-                var gameBone = skin.GetIGameBone(index, false);
-
-                var sortedIndex = skinSortedBones[skin].IndexOf(gameBone.NodeID);
-
-                gameBones[sortedIndex] = (gameBone);
-                boneIds[sortedIndex] =(gameBone.NodeID);
-                bones[sortedIndex]=(new BabylonBone { index = sortedIndex, name = gameBone.Name });
-
-                var boneInitMatrix = gameBone.GetObjectTM(0);
-                bindPoseInfos[sortedIndex] = (new BonePoseInfo { AbsoluteTransform = boneInitMatrix });
-            }
-
-            // fix hierarchy an generate animation keys
-            var exportNonOptimizedAnimations = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportnonoptimizedanimations");
-
-            for (var index = 0; index < skin.TotalSkinBoneCount; index++)
-            {
-                var gameBone = gameBones[index];
-                var parent = gameBone.NodeParent;
-                var babBone = bones[index];
-                if (parent != null)
-                {
-                    babBone.parentBoneIndex = boneIds.IndexOf(parent.NodeID);
-                }
-                if (babBone.parentBoneIndex == -1)
-                {
-                    bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform.Multiply(skinInitMatrix.Inverse);
-                }
-                else
-                {
-                    var parentBindPoseInfos = bindPoseInfos[babBone.parentBoneIndex];
-                    bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform.Multiply(parentBindPoseInfos.AbsoluteTransform.Inverse);
-                }
-                babBone.matrix = bindPoseInfos[index].LocalTransform.ToArray();
-
-                var babylonAnimation = new BabylonAnimation
-                {
-                    name = gameBone.Name + "Animation",
-                    property = "_matrix",
-                    dataType = (int)BabylonAnimation.DataType.Matrix,
-                    loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle,
-                    framePerSecond = Loader.Global.FrameRate
-                };
-
-                var start = Loader.Core.AnimRange.Start;
-                var end = Loader.Core.AnimRange.End;
-
-                float[] previous = null;
-                var keys = new List<BabylonAnimationKey>();
-                for (var key = start; key <= end; key += Ticks)
-                {
-                    var objectTM = gameBone.GetObjectTM(key);
-                    var parentNode = gameBone.NodeParent;
-                    IGMatrix mat;
-                    if (parentNode == null || babBone.parentBoneIndex == -1)
-                    {
-                        mat = objectTM.Multiply(meshNode.GetObjectTM(key).Inverse);
-                    }
-                    else
-                    {
-                        mat = objectTM.Multiply(parentNode.GetObjectTM(key).Inverse);
-                    }
-
-                    var current = mat.ToArray();
-                    if (key == start || key == end || exportNonOptimizedAnimations || !(previous.IsEqualTo(current)))
-                    {
-                        keys.Add(new BabylonAnimationKey
-                        {
-                            frame = key / Ticks,
-                            values = current
-                        });
-                    }
-
-                    previous = current;
-                }
-
-                babylonAnimation.keys = keys.ToArray();
-                babBone.animation = babylonAnimation;
-            }
-
-            babylonSkeleton.bones = bones.ToArray();
-
-            babylonScene.SkeletonsList.Add(babylonSkeleton);
-        }
-    }
-}
+using System;
+using System.Collections.Generic;
+using Autodesk.Max;
+using BabylonExport.Entities;
+using SharpDX;
+
+namespace Max2Babylon
+{
+    internal class BonePoseInfo
+    {
+        public IGMatrix AbsoluteTransform { get; set; }
+        public IGMatrix LocalTransform { get; set; }
+    }
+    partial class BabylonExporter
+    {
+        readonly List<IIGameSkin> skins = new List<IIGameSkin>();
+        readonly List<IIGameNode> skinnedNodes = new List<IIGameNode>();
+
+        IGMatrix WithNoScale(IGMatrix mat)
+        {
+            var mat3 = mat.ExtractMatrix3();
+            mat3.NoScale();
+            return Loader.Global.GMatrix.Create(mat3);
+        }
+        private void ExportSkin(IIGameSkin skin, BabylonScene babylonScene)
+        {
+            var babylonSkeleton = new BabylonSkeleton { id = skins.IndexOf(skin) };
+            babylonSkeleton.name = "skeleton #" + babylonSkeleton.id;
+
+            RaiseMessage(babylonSkeleton.name, 1);
+
+            var skinIndex = skins.IndexOf(skin);
+
+            var bones = new List<BabylonBone>();
+            var gameBones = new List<IIGameNode>();
+            var boneIds = new List<int>();
+            var bindPoseInfos = new List<BonePoseInfo>();
+            for(int i = 0; i < skin.TotalSkinBoneCount; ++i)
+            {
+                bones.Add(null);
+                gameBones.Add(null);
+                boneIds.Add(-1);
+                bindPoseInfos.Add(null);
+            }
+            for (var index = 0; index < skin.TotalSkinBoneCount; index++)
+            {
+                var gameBone = skin.GetIGameBone(index, false);
+
+                var sortedIndex = skinSortedBones[skin].IndexOf(gameBone.NodeID);
+
+                gameBones[sortedIndex] = (gameBone);
+                boneIds[sortedIndex] =(gameBone.NodeID);
+                bones[sortedIndex]=(new BabylonBone { index = sortedIndex, name = gameBone.Name });
+
+                var boneInitMatrix = gameBone.GetObjectTM(0);
+                bindPoseInfos[sortedIndex] = (new BonePoseInfo { AbsoluteTransform = boneInitMatrix });
+            }
+
+            // fix hierarchy an generate animation keys
+            var exportNonOptimizedAnimations = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportnonoptimizedanimations");
+
+            for (var index = 0; index < skin.TotalSkinBoneCount; index++)
+            {
+                var gameBone = gameBones[index];
+                var parent = gameBone.NodeParent;
+                var babBone = bones[index];
+                if (parent != null)
+                {
+                    babBone.parentBoneIndex = boneIds.IndexOf(parent.NodeID);
+                }
+
+                if (babBone.parentBoneIndex == -1)
+                {
+                    bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform;
+                }
+                else
+                {
+                    var parentBindPoseInfos = bindPoseInfos[babBone.parentBoneIndex];
+                    bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform.Multiply(parentBindPoseInfos.AbsoluteTransform.Inverse);
+                }
+
+                babBone.matrix = bindPoseInfos[index].LocalTransform.ToArray();
+
+                var babylonAnimation = new BabylonAnimation
+                {
+                    name = gameBone.Name + "Animation",
+                    property = "_matrix",
+                    dataType = (int)BabylonAnimation.DataType.Matrix,
+                    loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle,
+                    framePerSecond = Loader.Global.FrameRate
+                };
+
+                var start = Loader.Core.AnimRange.Start;
+                var end = Loader.Core.AnimRange.End;
+
+                float[] previous = null;
+                var keys = new List<BabylonAnimationKey>();
+                for (var key = start; key <= end; key += Ticks)
+                {
+                    var objectTM = gameBone.GetObjectTM(key);
+                    var parentNode = gameBone.NodeParent;
+                    IGMatrix mat;
+                    if (parentNode == null || babBone.parentBoneIndex == -1)
+                    {
+                        mat = objectTM;
+                    }
+                    else
+                    {
+                        mat = objectTM.Multiply(parentNode.GetObjectTM(key).Inverse);
+                    }
+
+                    var current = mat.ToArray();
+                    if (key == start || key == end || exportNonOptimizedAnimations || !(previous.IsEqualTo(current)))
+                    {
+                        keys.Add(new BabylonAnimationKey
+                        {
+                            frame = key / Ticks,
+                            values = current
+                        });
+                    }
+
+                    previous = current;
+                }
+
+                babylonAnimation.keys = keys.ToArray();
+                babBone.animation = babylonAnimation;
+            }
+
+            babylonSkeleton.needInitialSkinMatrix = true;
+            babylonSkeleton.bones = bones.ToArray();
+
+            babylonScene.SkeletonsList.Add(babylonSkeleton);
+        }
+    }
+}

+ 249 - 244
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Texture.cs

@@ -1,244 +1,249 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using Autodesk.Max;
-using BabylonExport.Entities;
-
-namespace Max2Babylon
-{
-    partial class BabylonExporter
-    {
-        bool IsTextureCube(string filepath)
-        {
-            try
-            {
-                if (Path.GetExtension(filepath).ToLower() != ".dds")
-                {
-                    return false;
-                }
-
-                var data = File.ReadAllBytes(filepath);
-                var intArray = new int[data.Length / 4];
-
-                Buffer.BlockCopy(data, 0, intArray, 0, intArray.Length * 4);
-
-
-                int width = intArray[4];
-                int height = intArray[3];
-                int mipmapsCount = intArray[7];
-
-                if ((width >> (mipmapsCount - 1)) > 1)
-                {
-                    var expected = 1;
-                    var currentSize = Math.Max(width, height);
-
-                    while (currentSize > 1)
-                    {
-                        currentSize = currentSize >> 1;
-                        expected++;
-                    }
-
-                    RaiseWarning(string.Format("Mipmaps chain is not complete: {0} maps instead of {1} (based on texture max size: {2})", mipmapsCount, expected, width), 2);
-                    RaiseWarning(string.Format("You must generate a complete mipmaps chain for .dds)"), 2);
-                    RaiseWarning(string.Format("Mipmaps will be disabled for this texture. If you want automatic texture generation you cannot use a .dds)"), 2);
-                }
-
-                bool isCube = (intArray[28] & 0x200) == 0x200;
-
-                return isCube;
-            }
-            catch
-            {
-                return false;
-            }
-        }
-
-        private BabylonTexture ExportTexture(IStdMat2 stdMat, int index, out BabylonFresnelParameters fresnelParameters, BabylonScene babylonScene, bool allowCube = false, bool forceAlpha = false)
-        {
-            fresnelParameters = null;
-
-            if (!stdMat.MapEnabled(index))
-            {
-                return null;
-            }
-            var babylonTexture = new BabylonTexture();
-
-            var texMap = stdMat.GetSubTexmap(index);
-
-            if (texMap == null)
-            {
-                RaiseWarning("Texture channel " + index + " activated but no texture found.");
-                return null;
-            }
-
-            // Fallout
-            if (texMap.ClassName == "Falloff") // This is the only way I found to detect it. This is crappy but it works
-            {
-                fresnelParameters = new BabylonFresnelParameters();
-
-                var paramBlock = texMap.GetParamBlock(0);
-                var color1 = paramBlock.GetColor(0, 0, 0);
-                var color2 = paramBlock.GetColor(4, 0, 0);
-
-                fresnelParameters.isEnabled = true;
-                fresnelParameters.leftColor = color2.ToArray();
-                fresnelParameters.rightColor = color1.ToArray();
-
-                if (paramBlock.GetInt(8, 0, 0) == 2)
-                {
-                    fresnelParameters.power = paramBlock.GetFloat(12, 0, 0);
-                }
-                else
-                {
-                    fresnelParameters.power = 1;
-                }
-                var texMap1 = paramBlock.GetTexmap(2, 0, 0);
-                var texMap1On = paramBlock.GetInt(3, 0, 0);
-
-                var texMap2 = paramBlock.GetTexmap(6, 0, 0);
-                var texMap2On = paramBlock.GetInt(7, 0, 0);
-
-                if (texMap1 != null && texMap1On != 0)
-                {
-                    texMap = texMap1;
-                    fresnelParameters.rightColor = new float[] { 1, 1, 1 };
-
-                    if (texMap2 != null && texMap2On != 0)
-                    {
-                        RaiseWarning(string.Format("You cannot specify two textures for falloff. Only one is supported"), 2);
-                    }
-                }
-                else if (texMap2 != null && texMap2On != 0)
-                {
-                    fresnelParameters.leftColor = new float[] { 1, 1, 1 };
-                    texMap = texMap2;
-                }
-                else
-                {
-                    return null;
-                }
-            }
-
-            // Bitmap
-            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;
-
-            if (texture == null)
-            {
-                return null;
-            }
-
-            if (forceAlpha)
-            {
-                babylonTexture.hasAlpha = true;
-                babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2) || (texture.AlphaSource == 3);
-            }
-            else
-            {
-                babylonTexture.hasAlpha = (texture.AlphaSource != 3);
-                babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2);
-            }
-
-
-            babylonTexture.level = stdMat.GetTexmapAmt(index, 0);
-
-            var uvGen = texture.UVGen;
-
-            switch (uvGen.GetCoordMapping(0))
-            {
-                case 1: //MAP_SPHERICAL
-                    babylonTexture.coordinatesMode = 1;
-                    break;
-                case 2: //MAP_PLANAR
-                    babylonTexture.coordinatesMode = 2;
-                    break;
-                default:
-                    babylonTexture.coordinatesMode = 0;
-                    break;
-            }
-
-            babylonTexture.coordinatesIndex = uvGen.MapChannel - 1;
-            if (uvGen.MapChannel > 2)
-            {
-                RaiseWarning(string.Format("Unsupported map channel, Only channel 1 and 2 are supported."), 2);
-            }
-
-            babylonTexture.uOffset = uvGen.GetUOffs(0);
-            babylonTexture.vOffset = uvGen.GetVOffs(0);
-
-            babylonTexture.uScale = uvGen.GetUScl(0);
-            babylonTexture.vScale = uvGen.GetVScl(0);
-
-            if (Path.GetExtension(texture.MapName).ToLower() == ".dds")
-            {
-                babylonTexture.vScale *= -1; // Need to invert Y-axis for DDS texture
-            }
-
-            babylonTexture.uAng = uvGen.GetUAng(0);
-            babylonTexture.vAng = uvGen.GetVAng(0);
-            babylonTexture.wAng = uvGen.GetWAng(0);
-
-            babylonTexture.wrapU = 0; // CLAMP
-            if ((uvGen.TextureTiling & 1) != 0) // WRAP
-            {
-                babylonTexture.wrapU = 1;
-            }
-            else if ((uvGen.TextureTiling & 4) != 0) // MIRROR
-            {
-                babylonTexture.wrapU = 2;
-            }
-
-            babylonTexture.wrapV = 0; // CLAMP
-            if ((uvGen.TextureTiling & 2) != 0) // WRAP
-            {
-                babylonTexture.wrapV = 1;
-            }
-            else if ((uvGen.TextureTiling & 8) != 0) // MIRROR
-            {
-                babylonTexture.wrapV = 2;
-            }
-
-            babylonTexture.name = Path.GetFileName(texture.MapName);
-
-            // Animations
-            var animations = new List<BabylonAnimation>();
-            ExportFloatAnimation("uOffset", animations, key => new[] { uvGen.GetUOffs(key) });
-            ExportFloatAnimation("vOffset", animations, key => new[] { uvGen.GetVOffs(key) });
-            ExportFloatAnimation("uScale", animations, key => new[] { uvGen.GetUScl(key) });
-            ExportFloatAnimation("vScale", animations, key => new[] { uvGen.GetVScl(key) });
-            ExportFloatAnimation("uAng", animations, key => new[] { uvGen.GetUAng(key) });
-            ExportFloatAnimation("vAng", animations, key => new[] { uvGen.GetVAng(key) });
-            ExportFloatAnimation("wAng", animations, key => new[] { uvGen.GetWAng(key) });
-
-            babylonTexture.animations = animations.ToArray();
-            var absolutePath = texture.Map.FullFilePath;
-            // Copy texture to output
-            try
-            {
-                if (File.Exists(absolutePath))
-                {
-                    babylonTexture.isCube = IsTextureCube(absolutePath);
-                    if (CopyTexturesToOutput)
-                    {
-                        File.Copy(absolutePath, Path.Combine(babylonScene.OutputPath, babylonTexture.name), true);
-                    }
-                }
-                else
-                {
-                    RaiseWarning(string.Format("Texture {0} not found.", babylonTexture.name), 2);
-                }
-
-            }
-            catch
-            {
-                // silently fails
-            }
-
-            if (babylonTexture.isCube && !allowCube)
-            {
-                RaiseWarning(string.Format("Cube texture are only supported for reflection channel"), 2);
-            }
-
-            return babylonTexture;
-        }
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Autodesk.Max;
+using BabylonExport.Entities;
+
+namespace Max2Babylon
+{
+    partial class BabylonExporter
+    {
+        bool IsTextureCube(string filepath)
+        {
+            try
+            {
+                if (Path.GetExtension(filepath).ToLower() != ".dds")
+                {
+                    return false;
+                }
+
+                var data = File.ReadAllBytes(filepath);
+                var intArray = new int[data.Length / 4];
+
+                Buffer.BlockCopy(data, 0, intArray, 0, intArray.Length * 4);
+
+
+                int width = intArray[4];
+                int height = intArray[3];
+                int mipmapsCount = intArray[7];
+
+                if ((width >> (mipmapsCount - 1)) > 1)
+                {
+                    var expected = 1;
+                    var currentSize = Math.Max(width, height);
+
+                    while (currentSize > 1)
+                    {
+                        currentSize = currentSize >> 1;
+                        expected++;
+                    }
+
+                    RaiseWarning(string.Format("Mipmaps chain is not complete: {0} maps instead of {1} (based on texture max size: {2})", mipmapsCount, expected, width), 2);
+                    RaiseWarning(string.Format("You must generate a complete mipmaps chain for .dds)"), 2);
+                    RaiseWarning(string.Format("Mipmaps will be disabled for this texture. If you want automatic texture generation you cannot use a .dds)"), 2);
+                }
+
+                bool isCube = (intArray[28] & 0x200) == 0x200;
+
+                return isCube;
+            }
+            catch
+            {
+                return false;
+            }
+        }
+
+        private BabylonTexture ExportTexture(IStdMat2 stdMat, int index, out BabylonFresnelParameters fresnelParameters, BabylonScene babylonScene, bool allowCube = false, bool forceAlpha = false)
+        {
+            fresnelParameters = null;
+
+            if (!stdMat.MapEnabled(index))
+            {
+                return null;
+            }
+            var babylonTexture = new BabylonTexture();
+
+            var texMap = stdMat.GetSubTexmap(index);
+
+            if (texMap == null)
+            {
+                RaiseWarning("Texture channel " + index + " activated but no texture found.");
+                return null;
+            }
+
+            // Fallout
+            if (texMap.ClassName == "Falloff") // This is the only way I found to detect it. This is crappy but it works
+            {
+                fresnelParameters = new BabylonFresnelParameters();
+
+                var paramBlock = texMap.GetParamBlock(0);
+                var color1 = paramBlock.GetColor(0, 0, 0);
+                var color2 = paramBlock.GetColor(4, 0, 0);
+
+                fresnelParameters.isEnabled = true;
+                fresnelParameters.leftColor = color2.ToArray();
+                fresnelParameters.rightColor = color1.ToArray();
+
+                if (paramBlock.GetInt(8, 0, 0) == 2)
+                {
+                    fresnelParameters.power = paramBlock.GetFloat(12, 0, 0);
+                }
+                else
+                {
+                    fresnelParameters.power = 1;
+                }
+                var texMap1 = paramBlock.GetTexmap(2, 0, 0);
+                var texMap1On = paramBlock.GetInt(3, 0, 0);
+
+                var texMap2 = paramBlock.GetTexmap(6, 0, 0);
+                var texMap2On = paramBlock.GetInt(7, 0, 0);
+
+                if (texMap1 != null && texMap1On != 0)
+                {
+                    texMap = texMap1;
+                    fresnelParameters.rightColor = new float[] { 1, 1, 1 };
+
+                    if (texMap2 != null && texMap2On != 0)
+                    {
+                        RaiseWarning(string.Format("You cannot specify two textures for falloff. Only one is supported"), 2);
+                    }
+                }
+                else if (texMap2 != null && texMap2On != 0)
+                {
+                    fresnelParameters.leftColor = new float[] { 1, 1, 1 };
+                    texMap = texMap2;
+                }
+                else
+                {
+                    return null;
+                }
+            }
+
+            // Bitmap
+            if (texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
+            {
+                return null;
+            }
+
+            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;
+
+            if (texture == null)
+            {
+                return null;
+            }
+
+            if (forceAlpha)
+            {
+                babylonTexture.hasAlpha = true;
+                babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2) || (texture.AlphaSource == 3);
+            }
+            else
+            {
+                babylonTexture.hasAlpha = (texture.AlphaSource != 3);
+                babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2);
+            }
+
+
+            babylonTexture.level = stdMat.GetTexmapAmt(index, 0);
+
+            var uvGen = texture.UVGen;
+
+            switch (uvGen.GetCoordMapping(0))
+            {
+                case 1: //MAP_SPHERICAL
+                    babylonTexture.coordinatesMode = 1;
+                    break;
+                case 2: //MAP_PLANAR
+                    babylonTexture.coordinatesMode = 2;
+                    break;
+                default:
+                    babylonTexture.coordinatesMode = 0;
+                    break;
+            }
+
+            babylonTexture.coordinatesIndex = uvGen.MapChannel - 1;
+            if (uvGen.MapChannel > 2)
+            {
+                RaiseWarning(string.Format("Unsupported map channel, Only channel 1 and 2 are supported."), 2);
+            }
+
+            babylonTexture.uOffset = uvGen.GetUOffs(0);
+            babylonTexture.vOffset = uvGen.GetVOffs(0);
+
+            babylonTexture.uScale = uvGen.GetUScl(0);
+            babylonTexture.vScale = uvGen.GetVScl(0);
+
+            if (Path.GetExtension(texture.MapName).ToLower() == ".dds")
+            {
+                babylonTexture.vScale *= -1; // Need to invert Y-axis for DDS texture
+            }
+
+            babylonTexture.uAng = uvGen.GetUAng(0);
+            babylonTexture.vAng = uvGen.GetVAng(0);
+            babylonTexture.wAng = uvGen.GetWAng(0);
+
+            babylonTexture.wrapU = 0; // CLAMP
+            if ((uvGen.TextureTiling & 1) != 0) // WRAP
+            {
+                babylonTexture.wrapU = 1;
+            }
+            else if ((uvGen.TextureTiling & 4) != 0) // MIRROR
+            {
+                babylonTexture.wrapU = 2;
+            }
+
+            babylonTexture.wrapV = 0; // CLAMP
+            if ((uvGen.TextureTiling & 2) != 0) // WRAP
+            {
+                babylonTexture.wrapV = 1;
+            }
+            else if ((uvGen.TextureTiling & 8) != 0) // MIRROR
+            {
+                babylonTexture.wrapV = 2;
+            }
+
+            babylonTexture.name = Path.GetFileName(texture.MapName);
+
+            // Animations
+            var animations = new List<BabylonAnimation>();
+            ExportFloatAnimation("uOffset", animations, key => new[] { uvGen.GetUOffs(key) });
+            ExportFloatAnimation("vOffset", animations, key => new[] { uvGen.GetVOffs(key) });
+            ExportFloatAnimation("uScale", animations, key => new[] { uvGen.GetUScl(key) });
+            ExportFloatAnimation("vScale", animations, key => new[] { uvGen.GetVScl(key) });
+            ExportFloatAnimation("uAng", animations, key => new[] { uvGen.GetUAng(key) });
+            ExportFloatAnimation("vAng", animations, key => new[] { uvGen.GetVAng(key) });
+            ExportFloatAnimation("wAng", animations, key => new[] { uvGen.GetWAng(key) });
+
+            babylonTexture.animations = animations.ToArray();
+            var absolutePath = texture.Map.FullFilePath;
+            // Copy texture to output
+            try
+            {
+                if (File.Exists(absolutePath))
+                {
+                    babylonTexture.isCube = IsTextureCube(absolutePath);
+                    if (CopyTexturesToOutput)
+                    {
+                        File.Copy(absolutePath, Path.Combine(babylonScene.OutputPath, babylonTexture.name), true);
+                    }
+                }
+                else
+                {
+                    RaiseWarning(string.Format("Texture {0} not found.", babylonTexture.name), 2);
+                }
+
+            }
+            catch
+            {
+                // silently fails
+            }
+
+            if (babylonTexture.isCube && !allowCube)
+            {
+                RaiseWarning(string.Format("Cube texture are only supported for reflection channel"), 2);
+            }
+
+            return babylonTexture;
+        }
+    }
+}

+ 351 - 322
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.cs

@@ -1,322 +1,351 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using Autodesk.Max;
-using BabylonExport.Entities;
-using Newtonsoft.Json;
-using Color = System.Drawing.Color;
-using System.Runtime.InteropServices;
-
-namespace Max2Babylon
-{
-    internal partial class BabylonExporter
-    {
-        public event Action<int> OnImportProgressChanged;
-        public event Action<string, int> OnWarning;
-        public event Action<string, Color, int, bool> OnMessage;
-        public event Action<string, int> OnError;
-
-        public bool AutoSave3dsMaxFile { get; set; }
-        public bool ExportHiddenObjects { get; set; }
-        public bool IsCancelled { get; set; }
-
-        public bool CopyTexturesToOutput { get; set; }
-
-        public string MaxSceneFileName { get; set; }
-
-        public bool ExportQuaternionsInsteadOfEulers { get; set; }
-
-        void ReportProgressChanged(int progress)
-        {
-            if (OnImportProgressChanged != null)
-            {
-                OnImportProgressChanged(progress);
-            }
-        }
-
-        void RaiseError(string error, int rank = 0)
-        {
-            if (OnError != null)
-            {
-                OnError(error, rank);
-            }
-        }
-
-        void RaiseWarning(string warning, int rank = 0)
-        {
-            if (OnWarning != null)
-            {
-                OnWarning(warning, rank);
-            }
-        }
-
-        void RaiseMessage(string message, int rank = 0, bool emphasis = false)
-        {
-            RaiseMessage(message, Color.Black, rank, emphasis);
-        }
-
-        void RaiseMessage(string message, Color color, int rank = 0, bool emphasis = false)
-        {
-            if (OnMessage != null)
-            {
-                OnMessage(message, color, rank, emphasis);
-            }
-        }
-
-        void CheckCancelled()
-        {
-            Application.DoEvents();
-            if (IsCancelled)
-            {
-                throw new OperationCanceledException();
-            }
-        }
-
-        public async Task ExportAsync(string outputFile, bool generateManifest, bool onlySelected, bool generateBinary, Form callerForm)
-        {
-            var gameConversionManger = Loader.Global.ConversionManager;
-            gameConversionManger.CoordSystem = Autodesk.Max.IGameConversionManager.CoordSystem.D3d;
-
-            var gameScene = Loader.Global.IGameInterface;
-            gameScene.InitialiseIGame(onlySelected);
-            gameScene.SetStaticFrame(0);
-
-            MaxSceneFileName = gameScene.SceneFileName;
-
-            IsCancelled = false;
-            RaiseMessage("Exportation started", Color.Blue);
-            ReportProgressChanged(0);
-            var babylonScene = new BabylonScene(Path.GetDirectoryName(outputFile));
-            var rawScene = Loader.Core.RootNode;
-
-            if (!Directory.Exists(babylonScene.OutputPath))
-            {
-                RaiseError("Exportation stopped: Output folder does not exist");
-                ReportProgressChanged(100);
-                return;
-            }
-
-            var watch = new Stopwatch();
-            watch.Start();
-
-            // Save scene
-            RaiseMessage("Saving 3ds max file");
-
-            if (AutoSave3dsMaxFile)
-            {
-                var forceSave = Loader.Core.FileSave;
-
-                if (callerForm != null)
-                {
-                    callerForm.BringToFront();
-                }
-            }
-
-            // Global
-            babylonScene.autoClear = true;
-            babylonScene.clearColor = Loader.Core.GetBackGround(0, Tools.Forever).ToArray();
-            babylonScene.ambientColor = Loader.Core.GetAmbient(0, Tools.Forever).ToArray();
-
-            babylonScene.gravity = rawScene.GetVector3Property("babylonjs_gravity");
-            ExportQuaternionsInsteadOfEulers = rawScene.GetBoolProperty("babylonjs_exportquaternions", 1);
-
-            // Sounds
-            var soundName = rawScene.GetStringProperty("babylonjs_sound_filename", "");
-
-            if (!string.IsNullOrEmpty(soundName))
-            {
-                var filename = Path.GetFileName(soundName);
-
-                var globalSound = new BabylonSound
-                {
-                    autoplay = rawScene.GetBoolProperty("babylonjs_sound_autoplay", 1),
-                    loop = rawScene.GetBoolProperty("babylonjs_sound_loop", 1),
-                    name = filename
-                };
-
-                babylonScene.SoundsList.Add(globalSound);
-
-                try
-                {
-                    File.Copy(soundName, Path.Combine(babylonScene.OutputPath, filename), true);
-                }
-                catch
-                {
-                }
-            }
-
-            // Cameras
-            BabylonCamera mainCamera = null;
-            ICameraObject mainCameraNode = null;
-
-            RaiseMessage("Exporting cameras");
-            var camerasTab = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Camera);
-            for (int ix = 0; ix < camerasTab.Count; ++ix)
-            {
-                var indexer = new IntPtr(ix);
-                var cameraNode = camerasTab[indexer];
-                Marshal.FreeHGlobal(indexer);
-                ExportCamera(gameScene, cameraNode, babylonScene);
-
-                if (mainCamera == null && babylonScene.CamerasList.Count > 0)
-                {
-                    mainCameraNode = (cameraNode.MaxNode.ObjectRef as ICameraObject);
-                    mainCamera = babylonScene.CamerasList[0];
-                    babylonScene.activeCameraID = mainCamera.id;
-                    RaiseMessage("Active camera set to " + mainCamera.name, Color.Green, 1, true);
-                }
-            }
-
-            if (mainCamera == null)
-            {
-                RaiseWarning("No camera defined", 1);
-            }
-            else
-            {
-                RaiseMessage(string.Format("Total: {0}", babylonScene.CamerasList.Count), Color.Gray, 1);
-            }
-
-            // Fog
-            for (var index = 0; index < Loader.Core.NumAtmospheric; index++)
-            {
-                var atmospheric = Loader.Core.GetAtmospheric(index);
-
-                if (atmospheric.Active(0) && atmospheric.ClassName == "Fog")
-                {
-                    var fog = atmospheric as IStdFog;
-
-                    RaiseMessage("Exporting fog");
-
-                    if (fog != null)
-                    {
-                        babylonScene.fogColor = fog.GetColor(0).ToArray();
-                        babylonScene.fogMode = 3;
-                    }
-#if !MAX2015 && !MAX2016
-                    else
-                    {
-                        var paramBlock = atmospheric.GetReference(0) as IIParamBlock;
-
-                        babylonScene.fogColor = Tools.GetParamBlockValueColor(paramBlock, "Fog Color");
-                        babylonScene.fogMode = 3;
-                    }
-#endif
-                    if (mainCamera != null)
-                    {
-                        babylonScene.fogStart = mainCameraNode.GetEnvRange(0, 0, Tools.Forever);
-                        babylonScene.fogEnd = mainCameraNode.GetEnvRange(0, 1, Tools.Forever);
-                    }
-                }
-            }
-
-            // Meshes
-            ReportProgressChanged(10);
-            RaiseMessage("Exporting meshes");
-            var meshes = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Mesh);
-            var progressionStep = 80.0f / meshes.Count;
-            var progression = 10.0f;
-            for (int ix = 0; ix < meshes.Count; ++ix)
-            {
-                var indexer = new IntPtr(ix);
-                var meshNode = meshes[indexer];
-                Marshal.FreeHGlobal(indexer);
-                ExportMesh(gameScene, meshNode, babylonScene);
-
-
-                ReportProgressChanged((int)progression);
-
-                progression += progressionStep;
-
-                CheckCancelled();
-            }
-
-
-            // Materials
-            RaiseMessage("Exporting materials");
-            var matsToExport = referencedMaterials.ToArray(); // Snapshot because multimaterials can export new materials
-            foreach (var mat in matsToExport)
-            {
-                ExportMaterial(mat, babylonScene);
-                CheckCancelled();
-            }
-            RaiseMessage(string.Format("Total: {0}", babylonScene.MaterialsList.Count + babylonScene.MultiMaterialsList.Count), Color.Gray, 1);
-
-            // Lights
-            RaiseMessage("Exporting lights");
-            var lightNodes = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Light);
-            for (var i = 0; i < lightNodes.Count; ++i)
-            {
-                ExportLight(gameScene, lightNodes[new IntPtr(i)], babylonScene);
-                CheckCancelled();
-            }
-
-
-            if (babylonScene.LightsList.Count == 0)
-            {
-                RaiseWarning("No light defined", 1);
-                RaiseWarning("A default hemispheric light was added for your convenience", 1);
-                ExportDefaultLight(babylonScene);
-            }
-            else
-            {
-                RaiseMessage(string.Format("Total: {0}", babylonScene.LightsList.Count), Color.Gray, 1);
-            }
-
-            // Skeletons
-            if (skins.Count > 0)
-            {
-                RaiseMessage("Exporting skeletons");
-                foreach (var skin in skins)
-                {
-                    ExportSkin(skin, babylonScene);
-                }
-            }
-
-            // Actions
-            babylonScene.actions = ExportNodeAction(gameScene.GetIGameNode(rawScene));
-
-            // Output
-            RaiseMessage("Saving to output file");
-            babylonScene.Prepare(false);
-            var jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings());
-            var sb = new StringBuilder();
-            var sw = new StringWriter(sb, CultureInfo.InvariantCulture);
-
-            await Task.Run(() =>
-            {
-                using (var jsonWriter = new JsonTextWriterOptimized(sw))
-                {
-                    jsonWriter.Formatting = Formatting.None;
-                    jsonSerializer.Serialize(jsonWriter, babylonScene);
-                }
-                File.WriteAllText(outputFile, sb.ToString());
-
-                if (generateManifest)
-                {
-                    File.WriteAllText(outputFile + ".manifest",
-                        "{\r\n\"version\" : 1,\r\n\"enableSceneOffline\" : true,\r\n\"enableTexturesOffline\" : true\r\n}");
-                }
-            });
-
-            // Binary
-            if (generateBinary)
-            {
-                RaiseMessage("Generating binary files");
-                BabylonFileConverter.BinaryConverter.Convert(outputFile, Path.GetDirectoryName(outputFile) + "\\Binary",
-                    message => RaiseMessage(message, 1),
-                    error => RaiseError(error, 1));
-            }
-
-            ReportProgressChanged(100);
-            watch.Stop();
-            RaiseMessage(string.Format("Exportation done in {0:0.00}s", watch.ElapsedMilliseconds / 1000.0), Color.Blue);
-        }
-
-
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Autodesk.Max;
+using BabylonExport.Entities;
+using Newtonsoft.Json;
+using Color = System.Drawing.Color;
+using System.Runtime.InteropServices;
+
+namespace Max2Babylon
+{
+    internal partial class BabylonExporter
+    {
+        public event Action<int> OnImportProgressChanged;
+        public event Action<string, int> OnWarning;
+        public event Action<string, Color, int, bool> OnMessage;
+        public event Action<string, int> OnError;
+
+        public bool AutoSave3dsMaxFile { get; set; }
+        public bool ExportHiddenObjects { get; set; }
+        public bool IsCancelled { get; set; }
+
+        public bool CopyTexturesToOutput { get; set; }
+
+        public string MaxSceneFileName { get; set; }
+
+        public bool ExportQuaternionsInsteadOfEulers { get; set; }
+
+        void ReportProgressChanged(int progress)
+        {
+            if (OnImportProgressChanged != null)
+            {
+                OnImportProgressChanged(progress);
+            }
+        }
+
+        void RaiseError(string error, int rank = 0)
+        {
+            if (OnError != null)
+            {
+                OnError(error, rank);
+            }
+        }
+
+        void RaiseWarning(string warning, int rank = 0)
+        {
+            if (OnWarning != null)
+            {
+                OnWarning(warning, rank);
+            }
+        }
+
+        void RaiseMessage(string message, int rank = 0, bool emphasis = false)
+        {
+            RaiseMessage(message, Color.Black, rank, emphasis);
+        }
+
+        void RaiseMessage(string message, Color color, int rank = 0, bool emphasis = false)
+        {
+            if (OnMessage != null)
+            {
+                OnMessage(message, color, rank, emphasis);
+            }
+        }
+
+        void CheckCancelled()
+        {
+            Application.DoEvents();
+            if (IsCancelled)
+            {
+                throw new OperationCanceledException();
+            }
+        }
+
+        public async Task ExportAsync(string outputFile, bool generateManifest, bool onlySelected, bool generateBinary, Form callerForm)
+        {
+            var gameConversionManger = Loader.Global.ConversionManager;
+            gameConversionManger.CoordSystem = Autodesk.Max.IGameConversionManager.CoordSystem.D3d;
+
+            var gameScene = Loader.Global.IGameInterface;
+            gameScene.InitialiseIGame(onlySelected);
+            gameScene.SetStaticFrame(0);
+
+            MaxSceneFileName = gameScene.SceneFileName;
+
+            IsCancelled = false;
+            RaiseMessage("Exportation started", Color.Blue);
+            ReportProgressChanged(0);
+            var babylonScene = new BabylonScene(Path.GetDirectoryName(outputFile));
+            var rawScene = Loader.Core.RootNode;
+
+            if (!Directory.Exists(babylonScene.OutputPath))
+            {
+                RaiseError("Exportation stopped: Output folder does not exist");
+                ReportProgressChanged(100);
+                return;
+            }
+
+            var watch = new Stopwatch();
+            watch.Start();
+
+            // Save scene
+            RaiseMessage("Saving 3ds max file");
+
+            if (AutoSave3dsMaxFile)
+            {
+                var forceSave = Loader.Core.FileSave;
+
+                callerForm?.BringToFront();
+            }
+
+            // Producer
+            babylonScene.producer = new BabylonProducer
+            {
+                name = "3dsmax",
+#if MAX2017
+                version = "2017",
+#else
+                version = Loader.Core.ProductVersion.ToString(),
+#endif
+                exporter_version = "0.4.5",
+                file = Path.GetFileName(outputFile)
+            };
+
+            // Global
+            babylonScene.autoClear = true;
+            babylonScene.clearColor = Loader.Core.GetBackGround(0, Tools.Forever).ToArray();
+            babylonScene.ambientColor = Loader.Core.GetAmbient(0, Tools.Forever).ToArray();
+
+            babylonScene.gravity = rawScene.GetVector3Property("babylonjs_gravity");
+            ExportQuaternionsInsteadOfEulers = rawScene.GetBoolProperty("babylonjs_exportquaternions", 1);
+
+            // Sounds
+            var soundName = rawScene.GetStringProperty("babylonjs_sound_filename", "");
+
+            if (!string.IsNullOrEmpty(soundName))
+            {
+                var filename = Path.GetFileName(soundName);
+
+                var globalSound = new BabylonSound
+                {
+                    autoplay = rawScene.GetBoolProperty("babylonjs_sound_autoplay", 1),
+                    loop = rawScene.GetBoolProperty("babylonjs_sound_loop", 1),
+                    name = filename
+                };
+
+                babylonScene.SoundsList.Add(globalSound);
+
+                try
+                {
+                    File.Copy(soundName, Path.Combine(babylonScene.OutputPath, filename), true);
+                }
+                catch
+                {
+                }
+            }
+
+            // Cameras
+            BabylonCamera mainCamera = null;
+            ICameraObject mainCameraNode = null;
+
+            RaiseMessage("Exporting cameras");
+            var camerasTab = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Camera);
+            for (int ix = 0; ix < camerasTab.Count; ++ix)
+            {
+#if MAX2017
+                var indexer = ix;
+#else
+                var indexer = new IntPtr(ix);
+#endif
+                var cameraNode = camerasTab[indexer];
+
+#if !MAX2017
+                Marshal.FreeHGlobal(indexer);
+#endif
+                
+                ExportCamera(gameScene, cameraNode, babylonScene);
+
+                if (mainCamera == null && babylonScene.CamerasList.Count > 0)
+                {
+                    mainCameraNode = (cameraNode.MaxNode.ObjectRef as ICameraObject);
+                    mainCamera = babylonScene.CamerasList[0];
+                    babylonScene.activeCameraID = mainCamera.id;
+                    RaiseMessage("Active camera set to " + mainCamera.name, Color.Green, 1, true);
+                }
+            }
+
+            if (mainCamera == null)
+            {
+                RaiseWarning("No camera defined", 1);
+            }
+            else
+            {
+                RaiseMessage(string.Format("Total: {0}", babylonScene.CamerasList.Count), Color.Gray, 1);
+            }
+
+            // Fog
+            for (var index = 0; index < Loader.Core.NumAtmospheric; index++)
+            {
+                var atmospheric = Loader.Core.GetAtmospheric(index);
+
+                if (atmospheric.Active(0) && atmospheric.ClassName == "Fog")
+                {
+                    var fog = atmospheric as IStdFog;
+
+                    RaiseMessage("Exporting fog");
+
+                    if (fog != null)
+                    {
+                        babylonScene.fogColor = fog.GetColor(0).ToArray();
+                        babylonScene.fogMode = 3;
+                    }
+#if !MAX2015 && !MAX2016 && !MAX2017
+                    else
+                    {
+                        var paramBlock = atmospheric.GetReference(0) as IIParamBlock;
+
+                        babylonScene.fogColor = Tools.GetParamBlockValueColor(paramBlock, "Fog Color");
+                        babylonScene.fogMode = 3;
+                    }
+#endif
+                    if (mainCamera != null)
+                    {
+                        babylonScene.fogStart = mainCameraNode.GetEnvRange(0, 0, Tools.Forever);
+                        babylonScene.fogEnd = mainCameraNode.GetEnvRange(0, 1, Tools.Forever);
+                    }
+                }
+            }
+
+            // Meshes
+            ReportProgressChanged(10);
+            RaiseMessage("Exporting meshes");
+            var meshes = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Mesh);
+            var progressionStep = 80.0f / meshes.Count;
+            var progression = 10.0f;
+            for (int ix = 0; ix < meshes.Count; ++ix)
+            {
+#if MAX2017
+                var indexer = ix;
+#else
+                var indexer = new IntPtr(ix);
+#endif
+                var meshNode = meshes[indexer];
+
+#if !MAX2017
+                Marshal.FreeHGlobal(indexer);
+#endif
+                ExportMesh(gameScene, meshNode, babylonScene);
+
+
+                ReportProgressChanged((int)progression);
+
+                progression += progressionStep;
+
+                CheckCancelled();
+            }
+
+
+            // Materials
+            RaiseMessage("Exporting materials");
+            var matsToExport = referencedMaterials.ToArray(); // Snapshot because multimaterials can export new materials
+            foreach (var mat in matsToExport)
+            {
+                ExportMaterial(mat, babylonScene);
+                CheckCancelled();
+            }
+            RaiseMessage(string.Format("Total: {0}", babylonScene.MaterialsList.Count + babylonScene.MultiMaterialsList.Count), Color.Gray, 1);
+
+            // Lights
+            RaiseMessage("Exporting lights");
+            var lightNodes = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Light);
+            for (var i = 0; i < lightNodes.Count; ++i)
+            {
+#if MAX2017
+                ExportLight(gameScene, lightNodes[i], babylonScene);
+#else
+                    ExportLight(gameScene, lightNodes[new IntPtr(i)], babylonScene);
+#endif
+                CheckCancelled();
+            }
+
+
+            if (babylonScene.LightsList.Count == 0)
+            {
+                RaiseWarning("No light defined", 1);
+                RaiseWarning("A default hemispheric light was added for your convenience", 1);
+                ExportDefaultLight(babylonScene);
+            }
+            else
+            {
+                RaiseMessage(string.Format("Total: {0}", babylonScene.LightsList.Count), Color.Gray, 1);
+            }
+
+            // Skeletons
+            if (skins.Count > 0)
+            {
+                RaiseMessage("Exporting skeletons");
+                foreach (var skin in skins)
+                {
+                    ExportSkin(skin, babylonScene);
+                }
+            }
+
+            // Actions
+            babylonScene.actions = ExportNodeAction(gameScene.GetIGameNode(rawScene));
+
+            // Output
+            RaiseMessage("Saving to output file");
+            babylonScene.Prepare(false);
+            var jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings());
+            var sb = new StringBuilder();
+            var sw = new StringWriter(sb, CultureInfo.InvariantCulture);
+
+            await Task.Run(() =>
+            {
+                using (var jsonWriter = new JsonTextWriterOptimized(sw))
+                {
+                    jsonWriter.Formatting = Formatting.None;
+                    jsonSerializer.Serialize(jsonWriter, babylonScene);
+                }
+                File.WriteAllText(outputFile, sb.ToString());
+
+                if (generateManifest)
+                {
+                    File.WriteAllText(outputFile + ".manifest",
+                        "{\r\n\"version\" : 1,\r\n\"enableSceneOffline\" : true,\r\n\"enableTexturesOffline\" : true\r\n}");
+                }
+            });
+
+            // Binary
+            if (generateBinary)
+            {
+                RaiseMessage("Generating binary files");
+                BabylonFileConverter.BinaryConverter.Convert(outputFile, Path.GetDirectoryName(outputFile) + "\\Binary",
+                    message => RaiseMessage(message, 1),
+                    error => RaiseError(error, 1));
+            }
+
+            ReportProgressChanged(100);
+            watch.Stop();
+            RaiseMessage(string.Format("Exportation done in {0:0.00}s", watch.ElapsedMilliseconds / 1000.0), Color.Blue);
+        }
+
+
+    }
+}

+ 76 - 69
Exporters/3ds Max/Max2Babylon/Exporter/GlobalVertex.cs

@@ -1,69 +1,76 @@
-using Autodesk.Max;
-
-namespace Max2Babylon
-{
-    public struct GlobalVertex
-    {
-        public int BaseIndex { get; set; }
-        public int CurrentIndex { get; set; }
-        public IPoint3 Position { get; set; }
-        public IPoint3 Normal { get; set; }
-        public IPoint2 UV { get; set; }
-        public IPoint2 UV2 { get; set; }
-        public int BonesIndices { get; set; }
-        public IPoint4 Weights { get; set; }
-        public float[] Color { get; set; }
-
-        public override int GetHashCode()
-        {
-            return base.GetHashCode();
-        }
-
-        public override bool Equals(object obj)
-        {
-            if (!(obj is GlobalVertex))
-            {
-                return false;
-            }
-
-            var other = (GlobalVertex)obj;
-
-            if (other.BaseIndex != BaseIndex)
-            {
-                return false;
-            }
-
-            if (!other.Position.IsAlmostEqualTo(Position, Tools.Epsilon))
-            {
-                return false;
-            }
-
-            if (!other.Normal.IsAlmostEqualTo(Normal, Tools.Epsilon))
-            {
-                return false;
-            }
-
-            if (UV != null && !other.UV.IsAlmostEqualTo(UV, Tools.Epsilon))
-            {
-                return false;
-            }
-
-            if (UV2 != null && !other.UV2.IsAlmostEqualTo(UV2, Tools.Epsilon))
-            {
-                return false;
-            }
-
-            if (Weights != null && !other.Weights.IsAlmostEqualTo(Weights, Tools.Epsilon))
-            {
-                return false;
-            }
-
-            if (Color != null && !other.Color.IsAlmostEqualTo(Color, Tools.Epsilon))
-            {
-                return false;
-            }
-
-            return other.BonesIndices == BonesIndices;
-        }
-    }
-}
+using Autodesk.Max;
+
+namespace Max2Babylon
+{
+    public struct GlobalVertex
+    {
+        public int BaseIndex { get; set; }
+        public int CurrentIndex { get; set; }
+        public IPoint3 Position { get; set; }
+        public IPoint3 Normal { get; set; }
+        public IPoint2 UV { get; set; }
+        public IPoint2 UV2 { get; set; }
+        public int BonesIndices { get; set; }
+        public IPoint4 Weights { get; set; }
+        public int BonesIndicesExtra { get; set; }
+        public IPoint4 WeightsExtra { get; set; }
+        public float[] Color { get; set; }
+
+        public override int GetHashCode()
+        {
+            return base.GetHashCode();
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (!(obj is GlobalVertex))
+            {
+                return false;
+            }
+
+            var other = (GlobalVertex)obj;
+
+            if (other.BaseIndex != BaseIndex)
+            {
+                return false;
+            }
+
+            if (!other.Position.IsAlmostEqualTo(Position, Tools.Epsilon))
+            {
+                return false;
+            }
+
+            if (!other.Normal.IsAlmostEqualTo(Normal, Tools.Epsilon))
+            {
+                return false;
+            }
+
+            if (UV != null && !other.UV.IsAlmostEqualTo(UV, Tools.Epsilon))
+            {
+                return false;
+            }
+
+            if (UV2 != null && !other.UV2.IsAlmostEqualTo(UV2, Tools.Epsilon))
+            {
+                return false;
+            }
+
+            if (Weights != null && !other.Weights.IsAlmostEqualTo(Weights, Tools.Epsilon))
+            {
+                return false;
+            }
+
+            if (WeightsExtra != null && !other.WeightsExtra.IsAlmostEqualTo(WeightsExtra, Tools.Epsilon))
+            {
+                return false;
+            }
+
+            if (Color != null && !other.Color.IsAlmostEqualTo(Color, Tools.Epsilon))
+            {
+                return false;
+            }
+
+            return other.BonesIndices == BonesIndices;
+        }
+    }
+}

+ 98 - 98
Exporters/3ds Max/Max2Babylon/Forms/ActionsBuilderForm.Designer.cs

@@ -1,99 +1,99 @@
-namespace Max2Babylon
-{
-    partial class ActionsBuilderForm
-    {
-        /// <summary>
-        /// Required designer variable.
-        /// </summary>
-        private System.ComponentModel.IContainer components = null;
-
-        /// <summary>
-        /// Clean up any resources being used.
-        /// </summary>
-        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing && (components != null))
-            {
-                components.Dispose();
-            }
-            base.Dispose(disposing);
-        }
-
-        #region Windows Form Designer generated code
-
-        /// <summary>
-        /// Required method for Designer support - do not modify
-        /// the contents of this method with the code editor.
-        /// </summary>
-        private void InitializeComponent()
-        {
-            this.ActionsBuilderWebView = new System.Windows.Forms.WebBrowser();
-            this.butCancel = new System.Windows.Forms.Button();
-            this.butOK = new System.Windows.Forms.Button();
-            this.SuspendLayout();
-            // 
-            // ActionsBuilderWebView
-            // 
-            this.ActionsBuilderWebView.AccessibleRole = System.Windows.Forms.AccessibleRole.Window;
-            this.ActionsBuilderWebView.AllowNavigation = false;
-            this.ActionsBuilderWebView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
-            | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-            this.ActionsBuilderWebView.IsWebBrowserContextMenuEnabled = false;
-            this.ActionsBuilderWebView.Location = new System.Drawing.Point(0, 0);
-            this.ActionsBuilderWebView.MinimumSize = new System.Drawing.Size(20, 20);
-            this.ActionsBuilderWebView.Name = "ActionsBuilderWebView";
-            this.ActionsBuilderWebView.Size = new System.Drawing.Size(723, 537);
-            this.ActionsBuilderWebView.TabIndex = 0;
-            this.ActionsBuilderWebView.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(this.ActionsBuilderWebView_DocumentCompleted);
-            // 
-            // butCancel
-            // 
-            this.butCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
-            this.butCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
-            this.butCancel.Location = new System.Drawing.Point(636, 544);
-            this.butCancel.Name = "butCancel";
-            this.butCancel.Size = new System.Drawing.Size(75, 23);
-            this.butCancel.TabIndex = 1;
-            this.butCancel.Text = "Cancel";
-            this.butCancel.UseVisualStyleBackColor = true;
-            this.butCancel.Click += new System.EventHandler(this.butCancel_Click);
-            // 
-            // butOK
-            // 
-            this.butOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
-            this.butOK.DialogResult = System.Windows.Forms.DialogResult.OK;
-            this.butOK.Location = new System.Drawing.Point(555, 544);
-            this.butOK.Name = "butOK";
-            this.butOK.Size = new System.Drawing.Size(75, 23);
-            this.butOK.TabIndex = 2;
-            this.butOK.Text = "OK";
-            this.butOK.UseVisualStyleBackColor = true;
-            this.butOK.Click += new System.EventHandler(this.butOK_Click);
-            // 
-            // ActionsBuilderForm
-            // 
-            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.ClientSize = new System.Drawing.Size(723, 579);
-            this.Controls.Add(this.butOK);
-            this.Controls.Add(this.butCancel);
-            this.Controls.Add(this.ActionsBuilderWebView);
-            this.Name = "ActionsBuilderForm";
-            this.Text = "Babylon.js Actions Builder";
-            this.Activated += new System.EventHandler(this.ActionsBuilderForm_Activated);
-            this.Deactivate += new System.EventHandler(this.ActionsBuilderForm_Deactivate);
-            this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ActionsBuilderForm_FormClosed);
-            this.Load += new System.EventHandler(this.ActionsBuilderForm_Load);
-            this.ResumeLayout(false);
-
-        }
-
-        #endregion
-
-        private System.Windows.Forms.WebBrowser ActionsBuilderWebView;
-        private System.Windows.Forms.Button butCancel;
-        private System.Windows.Forms.Button butOK;
-    }
+namespace Max2Babylon
+{
+    partial class ActionsBuilderForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.ActionsBuilderWebView = new System.Windows.Forms.WebBrowser();
+            this.butCancel = new System.Windows.Forms.Button();
+            this.butOK = new System.Windows.Forms.Button();
+            this.SuspendLayout();
+            // 
+            // ActionsBuilderWebView
+            // 
+            this.ActionsBuilderWebView.AccessibleRole = System.Windows.Forms.AccessibleRole.Window;
+            this.ActionsBuilderWebView.AllowNavigation = false;
+            this.ActionsBuilderWebView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.ActionsBuilderWebView.IsWebBrowserContextMenuEnabled = false;
+            this.ActionsBuilderWebView.Location = new System.Drawing.Point(0, 0);
+            this.ActionsBuilderWebView.MinimumSize = new System.Drawing.Size(20, 20);
+            this.ActionsBuilderWebView.Name = "ActionsBuilderWebView";
+            this.ActionsBuilderWebView.Size = new System.Drawing.Size(723, 537);
+            this.ActionsBuilderWebView.TabIndex = 0;
+            this.ActionsBuilderWebView.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler(this.ActionsBuilderWebView_DocumentCompleted);
+            // 
+            // butCancel
+            // 
+            this.butCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+            this.butCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.butCancel.Location = new System.Drawing.Point(636, 544);
+            this.butCancel.Name = "butCancel";
+            this.butCancel.Size = new System.Drawing.Size(75, 23);
+            this.butCancel.TabIndex = 1;
+            this.butCancel.Text = "Cancel";
+            this.butCancel.UseVisualStyleBackColor = true;
+            this.butCancel.Click += new System.EventHandler(this.butCancel_Click);
+            // 
+            // butOK
+            // 
+            this.butOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+            this.butOK.DialogResult = System.Windows.Forms.DialogResult.OK;
+            this.butOK.Location = new System.Drawing.Point(555, 544);
+            this.butOK.Name = "butOK";
+            this.butOK.Size = new System.Drawing.Size(75, 23);
+            this.butOK.TabIndex = 2;
+            this.butOK.Text = "OK";
+            this.butOK.UseVisualStyleBackColor = true;
+            this.butOK.Click += new System.EventHandler(this.butOK_Click);
+            // 
+            // ActionsBuilderForm
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(723, 579);
+            this.Controls.Add(this.butOK);
+            this.Controls.Add(this.butCancel);
+            this.Controls.Add(this.ActionsBuilderWebView);
+            this.Name = "ActionsBuilderForm";
+            this.Text = "Babylon.js Actions Builder";
+            this.Activated += new System.EventHandler(this.ActionsBuilderForm_Activated);
+            this.Deactivate += new System.EventHandler(this.ActionsBuilderForm_Deactivate);
+            this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ActionsBuilderForm_FormClosed);
+            this.Load += new System.EventHandler(this.ActionsBuilderForm_Load);
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.WebBrowser ActionsBuilderWebView;
+        private System.Windows.Forms.Button butCancel;
+        private System.Windows.Forms.Button butOK;
+    }
 }

+ 178 - 170
Exporters/3ds Max/Max2Babylon/Forms/ActionsBuilderForm.cs

@@ -1,170 +1,178 @@
-using System;
-using System.IO;
-using System.Collections.Generic;
-using System.Windows.Forms;
-using Autodesk.Max;
-using System.Runtime.InteropServices;
-
-namespace Max2Babylon
-{
-
-    public partial class ActionsBuilderForm : Form
-    {
-        private readonly BabylonActionsBuilderActionItem _babylonActionsBuilderAction;
-        private IINode _node = null;
-
-        private HtmlDocument _document;
-        private string _objectName;
-        private string _propertyName = "babylon_actionsbuilder";
-        private string _jsonResult = "";
-        private bool isRootNode;
-
-        public ActionsBuilderForm(BabylonActionsBuilderActionItem babylonActionsBuilderAction)
-        {
-            InitializeComponent();
-
-            // Finish
-            _babylonActionsBuilderAction = babylonActionsBuilderAction;
-        }
-        
-        private void ActionsBuilderForm_Load(object sender, EventArgs e)
-        {
-            if (Loader.Core.SelNodeCount > 0)
-            {
-                isRootNode = false;
-                _node = Loader.Core.GetSelNode(0);
-            }
-            else
-            {
-                isRootNode = true;
-                _node = Loader.Core.RootNode;
-            }
-            _objectName = _node.Name;
-
-            // Set url (webview)
-            string assemblyPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
-            ActionsBuilderWebView.Url = new Uri(string.Format("{0}/BabylonActionsBuilder/index.html", assemblyPath), System.UriKind.Absolute);
-        }
-
-        private void ActionsBuilderForm_FormClosed(object sender, FormClosedEventArgs e)
-        {
-            _babylonActionsBuilderAction.Close();
-        }
-
-        private void fillObjectsList(ITab<IIGameNode> list, string scriptName)
-        {
-            object[] names = new object[list.Count];
-            for (int i = 0; i < list.Count; i++)
-            {
-                var indexer = new IntPtr(i);
-                var node = list[indexer];
-                names[i] = node.MaxNode.Name;
-            }
-            _document.InvokeScript(scriptName, names);
-        }
-
-        private void fillSoundsList(ITab<IIGameNode> list, string scriptName)
-        {
-            object[] names = new object[list.Count];
-            for (int i = 0; i < list.Count; i++)
-            {
-                var indexer = new IntPtr(i);
-                var node = list[indexer].MaxNode;
-                string soundFile = "";
-
-                soundFile = Tools.GetStringProperty(node, "babylonjs_sound_filename", soundFile);
-                names[i] = Path.GetFileName(soundFile);
-            }
-            _document.InvokeScript(scriptName, names);
-        }
-
-        private void ActionsBuilderWebView_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
-        {
-            // Set common properties (name, is scene or object, etc.)
-            _document = ActionsBuilderWebView.Document;
-
-            // Update screen
-            _document.InvokeScript("hideButtons");
-
-            // Set object name
-            _document.GetElementById("ActionsBuilderObjectName").SetAttribute("value", _objectName);
-            _document.InvokeScript("updateObjectName");
-
-            if (isRootNode)
-                _document.InvokeScript("setIsScene");
-            else
-                _document.InvokeScript("setIsObject");
-
-            //_document.InvokeScript("updateObjectName");
-
-            if (getProperty())
-            {
-                _document.GetElementById("ActionsBuilderJSON").SetAttribute("value", _jsonResult);
-                _document.InvokeScript("loadFromJSON");
-            }
-
-            // Set lists of meshes, lights, cameras etc.
-            var gameScene = Loader.Global.IGameInterface;
-            gameScene.InitialiseIGame(false);
-
-            var meshes = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Mesh);
-            fillObjectsList(meshes, "setMeshesNames");
-
-            var lights = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Light);
-            fillObjectsList(lights, "setLightsNames");
-
-            var cameras = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Camera);
-            fillObjectsList(cameras, "setCamerasNames");
-
-            fillSoundsList(meshes, "setSoundsNames");
-
-            // Finish
-            _document.InvokeScript("resetList");
-
-            // Need to subclass this, then allow 3ds Max usage 
-            //Win32.SubClass(this.ActionsBuilderWebView.Handle);
-        }
-
-        private void butOK_Click(object sender, EventArgs e)
-        {
-            _document.InvokeScript("createJSON");
-            _jsonResult = _document.GetElementById("ActionsBuilderJSON").GetAttribute("value");
-
-            setProperty();
-
-            _babylonActionsBuilderAction.Close();
-        }
-
-        private void ActionsBuilderForm_Activated(object sender, EventArgs e)
-        {
-            Loader.Global.DisableAccelerators();
-        }
-
-        private void ActionsBuilderForm_Deactivate(object sender, EventArgs e)
-        {
-            Loader.Global.EnableAccelerators();
-        }
-
-        private void setProperty()
-        {
-            if (_node != null)
-                Tools.SetStringProperty(_node, _propertyName, _jsonResult);
-        }
-
-        private bool getProperty()
-        {
-            if (_node != null)
-                _jsonResult = Tools.GetStringProperty(_node, _propertyName, _jsonResult);
-            else
-                return false;
-
-            return true;
-        }
-
-        private void butCancel_Click(object sender, EventArgs e)
-        {
-            _babylonActionsBuilderAction.Close();
-        }
-    }
-
-}
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Windows.Forms;
+using Autodesk.Max;
+using System.Runtime.InteropServices;
+
+namespace Max2Babylon
+{
+
+    public partial class ActionsBuilderForm : Form
+    {
+        private readonly BabylonActionsBuilderActionItem _babylonActionsBuilderAction;
+        private IINode _node = null;
+
+        private HtmlDocument _document;
+        private string _objectName;
+        private string _propertyName = "babylon_actionsbuilder";
+        private string _jsonResult = "";
+        private bool isRootNode;
+
+        public ActionsBuilderForm(BabylonActionsBuilderActionItem babylonActionsBuilderAction)
+        {
+            InitializeComponent();
+
+            // Finish
+            _babylonActionsBuilderAction = babylonActionsBuilderAction;
+        }
+        
+        private void ActionsBuilderForm_Load(object sender, EventArgs e)
+        {
+            if (Loader.Core.SelNodeCount > 0)
+            {
+                isRootNode = false;
+                _node = Loader.Core.GetSelNode(0);
+            }
+            else
+            {
+                isRootNode = true;
+                _node = Loader.Core.RootNode;
+            }
+            _objectName = _node.Name;
+
+            // Set url (web view)
+            string assemblyPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
+            ActionsBuilderWebView.Url = new Uri(string.Format("{0}/BabylonActionsBuilder/index.html", assemblyPath), System.UriKind.Absolute);
+        }
+
+        private void ActionsBuilderForm_FormClosed(object sender, FormClosedEventArgs e)
+        {
+            _babylonActionsBuilderAction.Close();
+        }
+
+        private void fillObjectsList(ITab<IIGameNode> list, string scriptName)
+        {
+            object[] names = new object[list.Count];
+            for (int i = 0; i < list.Count; i++)
+            {
+#if MAX2017
+                var indexer = i;
+#else
+                var indexer = new IntPtr(i);
+#endif
+                var node = list[indexer];
+                names[i] = node.MaxNode.Name;
+            }
+            _document.InvokeScript(scriptName, names);
+        }
+
+        private void fillSoundsList(ITab<IIGameNode> list, string scriptName)
+        {
+            object[] names = new object[list.Count];
+            for (int i = 0; i < list.Count; i++)
+            {
+#if MAX2017
+                var indexer = i;
+#else
+                var indexer = new IntPtr(i);
+#endif
+                var node = list[indexer].MaxNode;
+                string soundFile = "";
+
+                soundFile = Tools.GetStringProperty(node, "babylonjs_sound_filename", soundFile);
+                names[i] = Path.GetFileName(soundFile);
+            }
+            _document.InvokeScript(scriptName, names);
+        }
+
+        private void ActionsBuilderWebView_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
+        {
+            // Set common properties (name, is scene or object, etc.)
+            _document = ActionsBuilderWebView.Document;
+
+            // Update version (no buttons for 3ds Max)
+            _document.InvokeScript("hideButtons");
+
+            // Set object name
+            _document.GetElementById("ActionsBuilderObjectName").SetAttribute("value", _objectName);
+            _document.InvokeScript("updateObjectName");
+
+            if (isRootNode)
+                _document.InvokeScript("setIsScene");
+            else
+                _document.InvokeScript("setIsObject");
+
+            //_document.InvokeScript("updateObjectName");
+
+            if (getProperty())
+            {
+                _document.GetElementById("ActionsBuilderJSON").SetAttribute("value", _jsonResult);
+                _document.InvokeScript("loadFromJSON");
+            }
+
+            // Set lists of meshes, lights, cameras etc.
+            var gameScene = Loader.Global.IGameInterface;
+            gameScene.InitialiseIGame(false);
+
+            var meshes = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Mesh);
+            fillObjectsList(meshes, "setMeshesNames");
+
+            var lights = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Light);
+            fillObjectsList(lights, "setLightsNames");
+
+            var cameras = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Camera);
+            fillObjectsList(cameras, "setCamerasNames");
+
+            fillSoundsList(meshes, "setSoundsNames");
+
+            // Finish
+            _document.InvokeScript("resetList");
+
+            // Need to subclass this, then allow 3ds Max usage 
+            //Win32.SubClass(this.ActionsBuilderWebView.Handle);
+        }
+
+        private void butOK_Click(object sender, EventArgs e)
+        {
+            _document.InvokeScript("createJSON");
+            _jsonResult = _document.GetElementById("ActionsBuilderJSON").GetAttribute("value");
+
+            setProperty();
+
+            _babylonActionsBuilderAction.Close();
+        }
+
+        private void ActionsBuilderForm_Activated(object sender, EventArgs e)
+        {
+            Loader.Global.DisableAccelerators();
+        }
+
+        private void ActionsBuilderForm_Deactivate(object sender, EventArgs e)
+        {
+            Loader.Global.EnableAccelerators();
+        }
+
+        private void setProperty()
+        {
+            if (_node != null)
+                Tools.SetStringProperty(_node, _propertyName, _jsonResult);
+        }
+
+        private bool getProperty()
+        {
+            if (_node != null)
+                _jsonResult = Tools.GetStringProperty(_node, _propertyName, _jsonResult);
+            else
+                return false;
+
+            return true;
+        }
+
+        private void butCancel_Click(object sender, EventArgs e)
+        {
+            _babylonActionsBuilderAction.Close();
+        }
+    }
+
+}

+ 119 - 119
Exporters/3ds Max/Max2Babylon/Forms/ActionsBuilderForm.resx

@@ -1,120 +1,120 @@
-<?xml version="1.0" encoding="utf-8"?>
-<root>
-  <!-- 
-    Microsoft ResX Schema 
-    
-    Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
-    associated with the data types.
-    
-    Example:
-    
-    ... ado.net/XML headers & schema ...
-    <resheader name="resmimetype">text/microsoft-resx</resheader>
-    <resheader name="version">2.0</resheader>
-    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
-    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
-    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
-    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
-    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
-        <value>[base64 mime encoded serialized .NET Framework object]</value>
-    </data>
-    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
-        <comment>This is a comment</comment>
-    </data>
-                
-    There are any number of "resheader" rows that contain simple 
-    name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
-    mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
-    extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
-    read any of the formats listed below.
-    
-    mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
-            : and then encoded with base64 encoding.
-    
-    mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
-            : and then encoded with base64 encoding.
-
-    mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
-            : using a System.ComponentModel.TypeConverter
-            : and then encoded with base64 encoding.
-    -->
-  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
-    <xsd:element name="root" msdata:IsDataSet="true">
-      <xsd:complexType>
-        <xsd:choice maxOccurs="unbounded">
-          <xsd:element name="metadata">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" />
-              </xsd:sequence>
-              <xsd:attribute name="name" use="required" type="xsd:string" />
-              <xsd:attribute name="type" type="xsd:string" />
-              <xsd:attribute name="mimetype" type="xsd:string" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="assembly">
-            <xsd:complexType>
-              <xsd:attribute name="alias" type="xsd:string" />
-              <xsd:attribute name="name" type="xsd:string" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="data">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
-              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
-              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="resheader">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" />
-            </xsd:complexType>
-          </xsd:element>
-        </xsd:choice>
-      </xsd:complexType>
-    </xsd:element>
-  </xsd:schema>
-  <resheader name="resmimetype">
-    <value>text/microsoft-resx</value>
-  </resheader>
-  <resheader name="version">
-    <value>2.0</value>
-  </resheader>
-  <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
 </root>

+ 415 - 415
Exporters/3ds Max/Max2Babylon/Forms/CameraPropertiesForm.Designer.cs

@@ -1,416 +1,416 @@
-namespace Max2Babylon
-{
-    partial class CameraPropertiesForm
-    {
-        /// <summary>
-        /// Required designer variable.
-        /// </summary>
-        private System.ComponentModel.IContainer components = null;
-
-        /// <summary>
-        /// Clean up any resources being used.
-        /// </summary>
-        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing && (components != null))
-            {
-                components.Dispose();
-            }
-            base.Dispose(disposing);
-        }
-
-        #region Windows Form Designer generated code
-
-        /// <summary>
-        /// Required method for Designer support - do not modify
-        /// the contents of this method with the code editor.
-        /// </summary>
-        private void InitializeComponent()
-        {
-            this.groupBox1 = new System.Windows.Forms.GroupBox();
-            this.ellipsoidControl = new Max2Babylon.Vector3Control();
-            this.label3 = new System.Windows.Forms.Label();
-            this.chkGravity = new System.Windows.Forms.CheckBox();
-            this.chkCollisions = new System.Windows.Forms.CheckBox();
-            this.butOK = new System.Windows.Forms.Button();
-            this.butCancel = new System.Windows.Forms.Button();
-            this.groupBox2 = new System.Windows.Forms.GroupBox();
-            this.label2 = new System.Windows.Forms.Label();
-            this.nupInertia = new System.Windows.Forms.NumericUpDown();
-            this.label1 = new System.Windows.Forms.Label();
-            this.nupSpeed = new System.Windows.Forms.NumericUpDown();
-            this.groupBox3 = new System.Windows.Forms.GroupBox();
-            this.grpAutoAnimate = new System.Windows.Forms.GroupBox();
-            this.chkLoop = new System.Windows.Forms.CheckBox();
-            this.nupTo = new System.Windows.Forms.NumericUpDown();
-            this.label4 = new System.Windows.Forms.Label();
-            this.nupFrom = new System.Windows.Forms.NumericUpDown();
-            this.label5 = new System.Windows.Forms.Label();
-            this.chkAutoAnimate = new System.Windows.Forms.CheckBox();
-            this.groupBox4 = new System.Windows.Forms.GroupBox();
-            this.label6 = new System.Windows.Forms.Label();
-            this.cbCameraType = new System.Windows.Forms.ComboBox();
-            this.chkNoExport = new System.Windows.Forms.CheckBox();
-            this.groupBox1.SuspendLayout();
-            this.groupBox2.SuspendLayout();
-            ((System.ComponentModel.ISupportInitialize)(this.nupInertia)).BeginInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupSpeed)).BeginInit();
-            this.groupBox3.SuspendLayout();
-            this.grpAutoAnimate.SuspendLayout();
-            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).BeginInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).BeginInit();
-            this.groupBox4.SuspendLayout();
-            this.SuspendLayout();
-            // 
-            // groupBox1
-            // 
-            this.groupBox1.Controls.Add(this.ellipsoidControl);
-            this.groupBox1.Controls.Add(this.label3);
-            this.groupBox1.Controls.Add(this.chkGravity);
-            this.groupBox1.Controls.Add(this.chkCollisions);
-            this.groupBox1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.groupBox1.Location = new System.Drawing.Point(12, 119);
-            this.groupBox1.Name = "groupBox1";
-            this.groupBox1.Size = new System.Drawing.Size(319, 138);
-            this.groupBox1.TabIndex = 0;
-            this.groupBox1.TabStop = false;
-            this.groupBox1.Text = "Collisions";
-            // 
-            // ellipsoidControl
-            // 
-            this.ellipsoidControl.Location = new System.Drawing.Point(21, 95);
-            this.ellipsoidControl.Name = "ellipsoidControl";
-            this.ellipsoidControl.Size = new System.Drawing.Size(294, 28);
-            this.ellipsoidControl.TabIndex = 3;
-            this.ellipsoidControl.X = 0F;
-            this.ellipsoidControl.Y = 0F;
-            this.ellipsoidControl.Z = 0F;
-            // 
-            // label3
-            // 
-            this.label3.AutoSize = true;
-            this.label3.Location = new System.Drawing.Point(18, 79);
-            this.label3.Name = "label3";
-            this.label3.Size = new System.Drawing.Size(48, 13);
-            this.label3.TabIndex = 2;
-            this.label3.Text = "Ellipsoid:";
-            // 
-            // chkGravity
-            // 
-            this.chkGravity.AutoSize = true;
-            this.chkGravity.Location = new System.Drawing.Point(21, 51);
-            this.chkGravity.Name = "chkGravity";
-            this.chkGravity.Size = new System.Drawing.Size(86, 17);
-            this.chkGravity.TabIndex = 1;
-            this.chkGravity.Text = "Apply gravity";
-            this.chkGravity.ThreeState = true;
-            this.chkGravity.UseVisualStyleBackColor = true;
-            // 
-            // chkCollisions
-            // 
-            this.chkCollisions.AutoSize = true;
-            this.chkCollisions.Location = new System.Drawing.Point(21, 28);
-            this.chkCollisions.Name = "chkCollisions";
-            this.chkCollisions.Size = new System.Drawing.Size(102, 17);
-            this.chkCollisions.TabIndex = 0;
-            this.chkCollisions.Text = "Check collisions";
-            this.chkCollisions.ThreeState = true;
-            this.chkCollisions.UseVisualStyleBackColor = true;
-            // 
-            // butOK
-            // 
-            this.butOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
-            this.butOK.DialogResult = System.Windows.Forms.DialogResult.OK;
-            this.butOK.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butOK.Location = new System.Drawing.Point(93, 578);
-            this.butOK.Name = "butOK";
-            this.butOK.Size = new System.Drawing.Size(75, 23);
-            this.butOK.TabIndex = 1;
-            this.butOK.Text = "OK";
-            this.butOK.UseVisualStyleBackColor = true;
-            this.butOK.Click += new System.EventHandler(this.butOK_Click);
-            // 
-            // butCancel
-            // 
-            this.butCancel.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
-            this.butCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
-            this.butCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butCancel.Location = new System.Drawing.Point(174, 578);
-            this.butCancel.Name = "butCancel";
-            this.butCancel.Size = new System.Drawing.Size(75, 23);
-            this.butCancel.TabIndex = 2;
-            this.butCancel.Text = "Cancel";
-            this.butCancel.UseVisualStyleBackColor = true;
-            // 
-            // groupBox2
-            // 
-            this.groupBox2.Controls.Add(this.label2);
-            this.groupBox2.Controls.Add(this.nupInertia);
-            this.groupBox2.Controls.Add(this.label1);
-            this.groupBox2.Controls.Add(this.nupSpeed);
-            this.groupBox2.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.groupBox2.Location = new System.Drawing.Point(12, 263);
-            this.groupBox2.Name = "groupBox2";
-            this.groupBox2.Size = new System.Drawing.Size(319, 140);
-            this.groupBox2.TabIndex = 3;
-            this.groupBox2.TabStop = false;
-            this.groupBox2.Text = "Control";
-            // 
-            // label2
-            // 
-            this.label2.AutoSize = true;
-            this.label2.Location = new System.Drawing.Point(21, 81);
-            this.label2.Name = "label2";
-            this.label2.Size = new System.Drawing.Size(36, 13);
-            this.label2.TabIndex = 3;
-            this.label2.Text = "Inertia";
-            // 
-            // nupInertia
-            // 
-            this.nupInertia.DecimalPlaces = 2;
-            this.nupInertia.Location = new System.Drawing.Point(24, 103);
-            this.nupInertia.Name = "nupInertia";
-            this.nupInertia.Size = new System.Drawing.Size(120, 20);
-            this.nupInertia.TabIndex = 2;
-            this.nupInertia.Value = new decimal(new int[] {
-            9,
-            0,
-            0,
-            65536});
-            // 
-            // label1
-            // 
-            this.label1.AutoSize = true;
-            this.label1.Location = new System.Drawing.Point(21, 28);
-            this.label1.Name = "label1";
-            this.label1.Size = new System.Drawing.Size(41, 13);
-            this.label1.TabIndex = 1;
-            this.label1.Text = "Speed:";
-            // 
-            // nupSpeed
-            // 
-            this.nupSpeed.DecimalPlaces = 1;
-            this.nupSpeed.Location = new System.Drawing.Point(24, 50);
-            this.nupSpeed.Name = "nupSpeed";
-            this.nupSpeed.Size = new System.Drawing.Size(120, 20);
-            this.nupSpeed.TabIndex = 0;
-            this.nupSpeed.Value = new decimal(new int[] {
-            1,
-            0,
-            0,
-            0});
-            // 
-            // groupBox3
-            // 
-            this.groupBox3.Controls.Add(this.grpAutoAnimate);
-            this.groupBox3.Controls.Add(this.chkAutoAnimate);
-            this.groupBox3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.groupBox3.Location = new System.Drawing.Point(12, 409);
-            this.groupBox3.Name = "groupBox3";
-            this.groupBox3.Size = new System.Drawing.Size(319, 156);
-            this.groupBox3.TabIndex = 5;
-            this.groupBox3.TabStop = false;
-            this.groupBox3.Text = "Animations";
-            // 
-            // grpAutoAnimate
-            // 
-            this.grpAutoAnimate.Controls.Add(this.chkLoop);
-            this.grpAutoAnimate.Controls.Add(this.nupTo);
-            this.grpAutoAnimate.Controls.Add(this.label4);
-            this.grpAutoAnimate.Controls.Add(this.nupFrom);
-            this.grpAutoAnimate.Controls.Add(this.label5);
-            this.grpAutoAnimate.Enabled = false;
-            this.grpAutoAnimate.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.grpAutoAnimate.Location = new System.Drawing.Point(21, 51);
-            this.grpAutoAnimate.Name = "grpAutoAnimate";
-            this.grpAutoAnimate.Size = new System.Drawing.Size(292, 99);
-            this.grpAutoAnimate.TabIndex = 3;
-            this.grpAutoAnimate.TabStop = false;
-            // 
-            // chkLoop
-            // 
-            this.chkLoop.AutoSize = true;
-            this.chkLoop.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.chkLoop.Location = new System.Drawing.Point(9, 66);
-            this.chkLoop.Name = "chkLoop";
-            this.chkLoop.Size = new System.Drawing.Size(47, 17);
-            this.chkLoop.TabIndex = 5;
-            this.chkLoop.Text = "Loop";
-            this.chkLoop.ThreeState = true;
-            this.chkLoop.UseVisualStyleBackColor = true;
-            // 
-            // nupTo
-            // 
-            this.nupTo.Location = new System.Drawing.Point(47, 40);
-            this.nupTo.Maximum = new decimal(new int[] {
-            1000,
-            0,
-            0,
-            0});
-            this.nupTo.Name = "nupTo";
-            this.nupTo.Size = new System.Drawing.Size(120, 20);
-            this.nupTo.TabIndex = 3;
-            // 
-            // label4
-            // 
-            this.label4.AutoSize = true;
-            this.label4.Location = new System.Drawing.Point(6, 42);
-            this.label4.Name = "label4";
-            this.label4.Size = new System.Drawing.Size(23, 13);
-            this.label4.TabIndex = 4;
-            this.label4.Text = "To:";
-            // 
-            // nupFrom
-            // 
-            this.nupFrom.Location = new System.Drawing.Point(47, 14);
-            this.nupFrom.Maximum = new decimal(new int[] {
-            1000,
-            0,
-            0,
-            0});
-            this.nupFrom.Name = "nupFrom";
-            this.nupFrom.Size = new System.Drawing.Size(120, 20);
-            this.nupFrom.TabIndex = 1;
-            // 
-            // label5
-            // 
-            this.label5.AutoSize = true;
-            this.label5.Location = new System.Drawing.Point(6, 16);
-            this.label5.Name = "label5";
-            this.label5.Size = new System.Drawing.Size(33, 13);
-            this.label5.TabIndex = 2;
-            this.label5.Text = "From:";
-            // 
-            // chkAutoAnimate
-            // 
-            this.chkAutoAnimate.AutoSize = true;
-            this.chkAutoAnimate.Location = new System.Drawing.Point(21, 28);
-            this.chkAutoAnimate.Name = "chkAutoAnimate";
-            this.chkAutoAnimate.Size = new System.Drawing.Size(88, 17);
-            this.chkAutoAnimate.TabIndex = 0;
-            this.chkAutoAnimate.Text = "Auto animate";
-            this.chkAutoAnimate.ThreeState = true;
-            this.chkAutoAnimate.UseVisualStyleBackColor = true;
-            this.chkAutoAnimate.CheckedChanged += new System.EventHandler(this.chkAutoAnimate_CheckedChanged);
-            // 
-            // groupBox4
-            // 
-            this.groupBox4.Controls.Add(this.label6);
-            this.groupBox4.Controls.Add(this.cbCameraType);
-            this.groupBox4.Controls.Add(this.chkNoExport);
-            this.groupBox4.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.groupBox4.Location = new System.Drawing.Point(12, 12);
-            this.groupBox4.Name = "groupBox4";
-            this.groupBox4.Size = new System.Drawing.Size(319, 101);
-            this.groupBox4.TabIndex = 6;
-            this.groupBox4.TabStop = false;
-            this.groupBox4.Text = "Misc.";
-            // 
-            // label6
-            // 
-            this.label6.AutoSize = true;
-            this.label6.Location = new System.Drawing.Point(16, 58);
-            this.label6.Name = "label6";
-            this.label6.Size = new System.Drawing.Size(34, 13);
-            this.label6.TabIndex = 6;
-            this.label6.Text = "Type:";
-            // 
-            // cbCameraType
-            // 
-            this.cbCameraType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
-            this.cbCameraType.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.cbCameraType.FormattingEnabled = true;
-            this.cbCameraType.Items.AddRange(new object[] {
-            "AnaglyphArcRotateCamera",
-            "AnaglyphFreeCamera",
-            "ArcRotateCamera",
-            "DeviceOrientationCamera",
-            "FollowCamera",
-            "FreeCamera",
-            "GamepadCamera",
-            "TouchCamera",
-            "VirtualJoysticksCamera",
-            "WebVRFreeCamera",
-            "VRDeviceOrientationFreeCamera"});
-            this.cbCameraType.Location = new System.Drawing.Point(23, 74);
-            this.cbCameraType.Name = "cbCameraType";
-            this.cbCameraType.Size = new System.Drawing.Size(290, 21);
-            this.cbCameraType.TabIndex = 5;
-            // 
-            // chkNoExport
-            // 
-            this.chkNoExport.AutoSize = true;
-            this.chkNoExport.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.chkNoExport.Location = new System.Drawing.Point(21, 28);
-            this.chkNoExport.Name = "chkNoExport";
-            this.chkNoExport.Size = new System.Drawing.Size(87, 17);
-            this.chkNoExport.TabIndex = 4;
-            this.chkNoExport.Text = "Do not export";
-            this.chkNoExport.ThreeState = true;
-            this.chkNoExport.UseVisualStyleBackColor = true;
-            // 
-            // CameraPropertiesForm
-            // 
-            this.AcceptButton = this.butOK;
-            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.CancelButton = this.butCancel;
-            this.ClientSize = new System.Drawing.Size(343, 613);
-            this.Controls.Add(this.groupBox4);
-            this.Controls.Add(this.groupBox3);
-            this.Controls.Add(this.groupBox2);
-            this.Controls.Add(this.butCancel);
-            this.Controls.Add(this.butOK);
-            this.Controls.Add(this.groupBox1);
-            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
-            this.Name = "CameraPropertiesForm";
-            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
-            this.Text = "Babylon.js - Camera Properties";
-            this.Load += new System.EventHandler(this.CameraPropertiesForm_Load);
-            this.groupBox1.ResumeLayout(false);
-            this.groupBox1.PerformLayout();
-            this.groupBox2.ResumeLayout(false);
-            this.groupBox2.PerformLayout();
-            ((System.ComponentModel.ISupportInitialize)(this.nupInertia)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupSpeed)).EndInit();
-            this.groupBox3.ResumeLayout(false);
-            this.groupBox3.PerformLayout();
-            this.grpAutoAnimate.ResumeLayout(false);
-            this.grpAutoAnimate.PerformLayout();
-            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).EndInit();
-            this.groupBox4.ResumeLayout(false);
-            this.groupBox4.PerformLayout();
-            this.ResumeLayout(false);
-
-        }
-
-        #endregion
-
-        private System.Windows.Forms.GroupBox groupBox1;
-        private System.Windows.Forms.Button butOK;
-        private System.Windows.Forms.Button butCancel;
-        private System.Windows.Forms.CheckBox chkCollisions;
-        private System.Windows.Forms.CheckBox chkGravity;
-        private System.Windows.Forms.GroupBox groupBox2;
-        private System.Windows.Forms.Label label1;
-        private System.Windows.Forms.NumericUpDown nupSpeed;
-        private System.Windows.Forms.Label label2;
-        private System.Windows.Forms.NumericUpDown nupInertia;
-        private System.Windows.Forms.Label label3;
-        private Vector3Control ellipsoidControl;
-        private System.Windows.Forms.GroupBox groupBox3;
-        private System.Windows.Forms.GroupBox grpAutoAnimate;
-        private System.Windows.Forms.CheckBox chkLoop;
-        private System.Windows.Forms.NumericUpDown nupTo;
-        private System.Windows.Forms.Label label4;
-        private System.Windows.Forms.NumericUpDown nupFrom;
-        private System.Windows.Forms.Label label5;
-        private System.Windows.Forms.CheckBox chkAutoAnimate;
-        private System.Windows.Forms.GroupBox groupBox4;
-        private System.Windows.Forms.CheckBox chkNoExport;
-        private System.Windows.Forms.Label label6;
-        private System.Windows.Forms.ComboBox cbCameraType;
-    }
+namespace Max2Babylon
+{
+    partial class CameraPropertiesForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.groupBox1 = new System.Windows.Forms.GroupBox();
+            this.ellipsoidControl = new Max2Babylon.Vector3Control();
+            this.label3 = new System.Windows.Forms.Label();
+            this.chkGravity = new System.Windows.Forms.CheckBox();
+            this.chkCollisions = new System.Windows.Forms.CheckBox();
+            this.butOK = new System.Windows.Forms.Button();
+            this.butCancel = new System.Windows.Forms.Button();
+            this.groupBox2 = new System.Windows.Forms.GroupBox();
+            this.label2 = new System.Windows.Forms.Label();
+            this.nupInertia = new System.Windows.Forms.NumericUpDown();
+            this.label1 = new System.Windows.Forms.Label();
+            this.nupSpeed = new System.Windows.Forms.NumericUpDown();
+            this.groupBox3 = new System.Windows.Forms.GroupBox();
+            this.grpAutoAnimate = new System.Windows.Forms.GroupBox();
+            this.chkLoop = new System.Windows.Forms.CheckBox();
+            this.nupTo = new System.Windows.Forms.NumericUpDown();
+            this.label4 = new System.Windows.Forms.Label();
+            this.nupFrom = new System.Windows.Forms.NumericUpDown();
+            this.label5 = new System.Windows.Forms.Label();
+            this.chkAutoAnimate = new System.Windows.Forms.CheckBox();
+            this.groupBox4 = new System.Windows.Forms.GroupBox();
+            this.label6 = new System.Windows.Forms.Label();
+            this.cbCameraType = new System.Windows.Forms.ComboBox();
+            this.chkNoExport = new System.Windows.Forms.CheckBox();
+            this.groupBox1.SuspendLayout();
+            this.groupBox2.SuspendLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupInertia)).BeginInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupSpeed)).BeginInit();
+            this.groupBox3.SuspendLayout();
+            this.grpAutoAnimate.SuspendLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).BeginInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).BeginInit();
+            this.groupBox4.SuspendLayout();
+            this.SuspendLayout();
+            // 
+            // groupBox1
+            // 
+            this.groupBox1.Controls.Add(this.ellipsoidControl);
+            this.groupBox1.Controls.Add(this.label3);
+            this.groupBox1.Controls.Add(this.chkGravity);
+            this.groupBox1.Controls.Add(this.chkCollisions);
+            this.groupBox1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.groupBox1.Location = new System.Drawing.Point(12, 119);
+            this.groupBox1.Name = "groupBox1";
+            this.groupBox1.Size = new System.Drawing.Size(319, 138);
+            this.groupBox1.TabIndex = 0;
+            this.groupBox1.TabStop = false;
+            this.groupBox1.Text = "Collisions";
+            // 
+            // ellipsoidControl
+            // 
+            this.ellipsoidControl.Location = new System.Drawing.Point(21, 95);
+            this.ellipsoidControl.Name = "ellipsoidControl";
+            this.ellipsoidControl.Size = new System.Drawing.Size(294, 28);
+            this.ellipsoidControl.TabIndex = 3;
+            this.ellipsoidControl.X = 0F;
+            this.ellipsoidControl.Y = 0F;
+            this.ellipsoidControl.Z = 0F;
+            // 
+            // label3
+            // 
+            this.label3.AutoSize = true;
+            this.label3.Location = new System.Drawing.Point(18, 79);
+            this.label3.Name = "label3";
+            this.label3.Size = new System.Drawing.Size(48, 13);
+            this.label3.TabIndex = 2;
+            this.label3.Text = "Ellipsoid:";
+            // 
+            // chkGravity
+            // 
+            this.chkGravity.AutoSize = true;
+            this.chkGravity.Location = new System.Drawing.Point(21, 51);
+            this.chkGravity.Name = "chkGravity";
+            this.chkGravity.Size = new System.Drawing.Size(86, 17);
+            this.chkGravity.TabIndex = 1;
+            this.chkGravity.Text = "Apply gravity";
+            this.chkGravity.ThreeState = true;
+            this.chkGravity.UseVisualStyleBackColor = true;
+            // 
+            // chkCollisions
+            // 
+            this.chkCollisions.AutoSize = true;
+            this.chkCollisions.Location = new System.Drawing.Point(21, 28);
+            this.chkCollisions.Name = "chkCollisions";
+            this.chkCollisions.Size = new System.Drawing.Size(102, 17);
+            this.chkCollisions.TabIndex = 0;
+            this.chkCollisions.Text = "Check collisions";
+            this.chkCollisions.ThreeState = true;
+            this.chkCollisions.UseVisualStyleBackColor = true;
+            // 
+            // butOK
+            // 
+            this.butOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
+            this.butOK.DialogResult = System.Windows.Forms.DialogResult.OK;
+            this.butOK.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.butOK.Location = new System.Drawing.Point(93, 578);
+            this.butOK.Name = "butOK";
+            this.butOK.Size = new System.Drawing.Size(75, 23);
+            this.butOK.TabIndex = 1;
+            this.butOK.Text = "OK";
+            this.butOK.UseVisualStyleBackColor = true;
+            this.butOK.Click += new System.EventHandler(this.butOK_Click);
+            // 
+            // butCancel
+            // 
+            this.butCancel.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
+            this.butCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.butCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.butCancel.Location = new System.Drawing.Point(174, 578);
+            this.butCancel.Name = "butCancel";
+            this.butCancel.Size = new System.Drawing.Size(75, 23);
+            this.butCancel.TabIndex = 2;
+            this.butCancel.Text = "Cancel";
+            this.butCancel.UseVisualStyleBackColor = true;
+            // 
+            // groupBox2
+            // 
+            this.groupBox2.Controls.Add(this.label2);
+            this.groupBox2.Controls.Add(this.nupInertia);
+            this.groupBox2.Controls.Add(this.label1);
+            this.groupBox2.Controls.Add(this.nupSpeed);
+            this.groupBox2.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.groupBox2.Location = new System.Drawing.Point(12, 263);
+            this.groupBox2.Name = "groupBox2";
+            this.groupBox2.Size = new System.Drawing.Size(319, 140);
+            this.groupBox2.TabIndex = 3;
+            this.groupBox2.TabStop = false;
+            this.groupBox2.Text = "Control";
+            // 
+            // label2
+            // 
+            this.label2.AutoSize = true;
+            this.label2.Location = new System.Drawing.Point(21, 81);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(36, 13);
+            this.label2.TabIndex = 3;
+            this.label2.Text = "Inertia";
+            // 
+            // nupInertia
+            // 
+            this.nupInertia.DecimalPlaces = 2;
+            this.nupInertia.Location = new System.Drawing.Point(24, 103);
+            this.nupInertia.Name = "nupInertia";
+            this.nupInertia.Size = new System.Drawing.Size(120, 20);
+            this.nupInertia.TabIndex = 2;
+            this.nupInertia.Value = new decimal(new int[] {
+            9,
+            0,
+            0,
+            65536});
+            // 
+            // label1
+            // 
+            this.label1.AutoSize = true;
+            this.label1.Location = new System.Drawing.Point(21, 28);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(41, 13);
+            this.label1.TabIndex = 1;
+            this.label1.Text = "Speed:";
+            // 
+            // nupSpeed
+            // 
+            this.nupSpeed.DecimalPlaces = 1;
+            this.nupSpeed.Location = new System.Drawing.Point(24, 50);
+            this.nupSpeed.Name = "nupSpeed";
+            this.nupSpeed.Size = new System.Drawing.Size(120, 20);
+            this.nupSpeed.TabIndex = 0;
+            this.nupSpeed.Value = new decimal(new int[] {
+            1,
+            0,
+            0,
+            0});
+            // 
+            // groupBox3
+            // 
+            this.groupBox3.Controls.Add(this.grpAutoAnimate);
+            this.groupBox3.Controls.Add(this.chkAutoAnimate);
+            this.groupBox3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.groupBox3.Location = new System.Drawing.Point(12, 409);
+            this.groupBox3.Name = "groupBox3";
+            this.groupBox3.Size = new System.Drawing.Size(319, 156);
+            this.groupBox3.TabIndex = 5;
+            this.groupBox3.TabStop = false;
+            this.groupBox3.Text = "Animations";
+            // 
+            // grpAutoAnimate
+            // 
+            this.grpAutoAnimate.Controls.Add(this.chkLoop);
+            this.grpAutoAnimate.Controls.Add(this.nupTo);
+            this.grpAutoAnimate.Controls.Add(this.label4);
+            this.grpAutoAnimate.Controls.Add(this.nupFrom);
+            this.grpAutoAnimate.Controls.Add(this.label5);
+            this.grpAutoAnimate.Enabled = false;
+            this.grpAutoAnimate.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.grpAutoAnimate.Location = new System.Drawing.Point(21, 51);
+            this.grpAutoAnimate.Name = "grpAutoAnimate";
+            this.grpAutoAnimate.Size = new System.Drawing.Size(292, 99);
+            this.grpAutoAnimate.TabIndex = 3;
+            this.grpAutoAnimate.TabStop = false;
+            // 
+            // chkLoop
+            // 
+            this.chkLoop.AutoSize = true;
+            this.chkLoop.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkLoop.Location = new System.Drawing.Point(9, 66);
+            this.chkLoop.Name = "chkLoop";
+            this.chkLoop.Size = new System.Drawing.Size(47, 17);
+            this.chkLoop.TabIndex = 5;
+            this.chkLoop.Text = "Loop";
+            this.chkLoop.ThreeState = true;
+            this.chkLoop.UseVisualStyleBackColor = true;
+            // 
+            // nupTo
+            // 
+            this.nupTo.Location = new System.Drawing.Point(47, 40);
+            this.nupTo.Maximum = new decimal(new int[] {
+            100000,
+            0,
+            0,
+            0});
+            this.nupTo.Name = "nupTo";
+            this.nupTo.Size = new System.Drawing.Size(120, 20);
+            this.nupTo.TabIndex = 3;
+            // 
+            // label4
+            // 
+            this.label4.AutoSize = true;
+            this.label4.Location = new System.Drawing.Point(6, 42);
+            this.label4.Name = "label4";
+            this.label4.Size = new System.Drawing.Size(23, 13);
+            this.label4.TabIndex = 4;
+            this.label4.Text = "To:";
+            // 
+            // nupFrom
+            // 
+            this.nupFrom.Location = new System.Drawing.Point(47, 14);
+            this.nupFrom.Maximum = new decimal(new int[] {
+            100000,
+            0,
+            0,
+            0});
+            this.nupFrom.Name = "nupFrom";
+            this.nupFrom.Size = new System.Drawing.Size(120, 20);
+            this.nupFrom.TabIndex = 1;
+            // 
+            // label5
+            // 
+            this.label5.AutoSize = true;
+            this.label5.Location = new System.Drawing.Point(6, 16);
+            this.label5.Name = "label5";
+            this.label5.Size = new System.Drawing.Size(33, 13);
+            this.label5.TabIndex = 2;
+            this.label5.Text = "From:";
+            // 
+            // chkAutoAnimate
+            // 
+            this.chkAutoAnimate.AutoSize = true;
+            this.chkAutoAnimate.Location = new System.Drawing.Point(21, 28);
+            this.chkAutoAnimate.Name = "chkAutoAnimate";
+            this.chkAutoAnimate.Size = new System.Drawing.Size(88, 17);
+            this.chkAutoAnimate.TabIndex = 0;
+            this.chkAutoAnimate.Text = "Auto animate";
+            this.chkAutoAnimate.ThreeState = true;
+            this.chkAutoAnimate.UseVisualStyleBackColor = true;
+            this.chkAutoAnimate.CheckedChanged += new System.EventHandler(this.chkAutoAnimate_CheckedChanged);
+            // 
+            // groupBox4
+            // 
+            this.groupBox4.Controls.Add(this.label6);
+            this.groupBox4.Controls.Add(this.cbCameraType);
+            this.groupBox4.Controls.Add(this.chkNoExport);
+            this.groupBox4.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.groupBox4.Location = new System.Drawing.Point(12, 12);
+            this.groupBox4.Name = "groupBox4";
+            this.groupBox4.Size = new System.Drawing.Size(319, 101);
+            this.groupBox4.TabIndex = 6;
+            this.groupBox4.TabStop = false;
+            this.groupBox4.Text = "Misc.";
+            // 
+            // label6
+            // 
+            this.label6.AutoSize = true;
+            this.label6.Location = new System.Drawing.Point(16, 58);
+            this.label6.Name = "label6";
+            this.label6.Size = new System.Drawing.Size(34, 13);
+            this.label6.TabIndex = 6;
+            this.label6.Text = "Type:";
+            // 
+            // cbCameraType
+            // 
+            this.cbCameraType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.cbCameraType.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.cbCameraType.FormattingEnabled = true;
+            this.cbCameraType.Items.AddRange(new object[] {
+            "AnaglyphArcRotateCamera",
+            "AnaglyphFreeCamera",
+            "ArcRotateCamera",
+            "DeviceOrientationCamera",
+            "FollowCamera",
+            "FreeCamera",
+            "GamepadCamera",
+            "TouchCamera",
+            "VirtualJoysticksCamera",
+            "WebVRFreeCamera",
+            "VRDeviceOrientationFreeCamera"});
+            this.cbCameraType.Location = new System.Drawing.Point(23, 74);
+            this.cbCameraType.Name = "cbCameraType";
+            this.cbCameraType.Size = new System.Drawing.Size(290, 21);
+            this.cbCameraType.TabIndex = 5;
+            // 
+            // chkNoExport
+            // 
+            this.chkNoExport.AutoSize = true;
+            this.chkNoExport.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkNoExport.Location = new System.Drawing.Point(21, 28);
+            this.chkNoExport.Name = "chkNoExport";
+            this.chkNoExport.Size = new System.Drawing.Size(87, 17);
+            this.chkNoExport.TabIndex = 4;
+            this.chkNoExport.Text = "Do not export";
+            this.chkNoExport.ThreeState = true;
+            this.chkNoExport.UseVisualStyleBackColor = true;
+            // 
+            // CameraPropertiesForm
+            // 
+            this.AcceptButton = this.butOK;
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.CancelButton = this.butCancel;
+            this.ClientSize = new System.Drawing.Size(343, 613);
+            this.Controls.Add(this.groupBox4);
+            this.Controls.Add(this.groupBox3);
+            this.Controls.Add(this.groupBox2);
+            this.Controls.Add(this.butCancel);
+            this.Controls.Add(this.butOK);
+            this.Controls.Add(this.groupBox1);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
+            this.Name = "CameraPropertiesForm";
+            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+            this.Text = "Babylon.js - Camera Properties";
+            this.Load += new System.EventHandler(this.CameraPropertiesForm_Load);
+            this.groupBox1.ResumeLayout(false);
+            this.groupBox1.PerformLayout();
+            this.groupBox2.ResumeLayout(false);
+            this.groupBox2.PerformLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupInertia)).EndInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupSpeed)).EndInit();
+            this.groupBox3.ResumeLayout(false);
+            this.groupBox3.PerformLayout();
+            this.grpAutoAnimate.ResumeLayout(false);
+            this.grpAutoAnimate.PerformLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).EndInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).EndInit();
+            this.groupBox4.ResumeLayout(false);
+            this.groupBox4.PerformLayout();
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.GroupBox groupBox1;
+        private System.Windows.Forms.Button butOK;
+        private System.Windows.Forms.Button butCancel;
+        private System.Windows.Forms.CheckBox chkCollisions;
+        private System.Windows.Forms.CheckBox chkGravity;
+        private System.Windows.Forms.GroupBox groupBox2;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.NumericUpDown nupSpeed;
+        private System.Windows.Forms.Label label2;
+        private System.Windows.Forms.NumericUpDown nupInertia;
+        private System.Windows.Forms.Label label3;
+        private Vector3Control ellipsoidControl;
+        private System.Windows.Forms.GroupBox groupBox3;
+        private System.Windows.Forms.GroupBox grpAutoAnimate;
+        private System.Windows.Forms.CheckBox chkLoop;
+        private System.Windows.Forms.NumericUpDown nupTo;
+        private System.Windows.Forms.Label label4;
+        private System.Windows.Forms.NumericUpDown nupFrom;
+        private System.Windows.Forms.Label label5;
+        private System.Windows.Forms.CheckBox chkAutoAnimate;
+        private System.Windows.Forms.GroupBox groupBox4;
+        private System.Windows.Forms.CheckBox chkNoExport;
+        private System.Windows.Forms.Label label6;
+        private System.Windows.Forms.ComboBox cbCameraType;
+    }
 }

+ 71 - 71
Exporters/3ds Max/Max2Babylon/Forms/CameraPropertiesForm.cs

@@ -1,71 +1,71 @@
-using System;
-using System.Collections.Generic;
-using System.Windows.Forms;
-using Autodesk.Max;
-
-namespace Max2Babylon
-{
-    public partial class CameraPropertiesForm : Form
-    {
-        private readonly List<IINode> cameras = new List<IINode>();
-
-        public CameraPropertiesForm()
-        {
-            InitializeComponent();
-        }
-
-        private void CameraPropertiesForm_Load(object sender, EventArgs e)
-        {
-            for (var index = 0; index < Loader.Core.SelNodeCount; index++)
-            {
-                var node = Loader.Core.GetSelNode(index);
-
-                if (node.ObjectRef != null && node.ObjectRef.Eval(0).Obj.SuperClassID == SClass_ID.Camera)
-                {
-                    cameras.Add(node);
-                }
-            }
-
-            Tools.PrepareCheckBox(chkNoExport, cameras, "babylonjs_noexport");
-            Tools.PrepareCheckBox(chkCollisions, cameras, "babylonjs_checkcollisions");
-            Tools.PrepareCheckBox(chkGravity, cameras, "babylonjs_applygravity");
-
-            Tools.PrepareNumericUpDown(nupSpeed, cameras, "babylonjs_speed", 1.0f);
-            Tools.PrepareNumericUpDown(nupInertia, cameras, "babylonjs_inertia", 0.9f);
-
-            Tools.PrepareVector3Control(ellipsoidControl, cameras[0], "babylonjs_ellipsoid", 0.5f, 1.0f, 0.5f);
-
-            Tools.PrepareComboBox(cbCameraType, cameras[0], "babylonjs_type", "FreeCamera");
-
-            Tools.PrepareCheckBox(chkAutoAnimate, cameras, "babylonjs_autoanimate");
-            Tools.PrepareCheckBox(chkLoop, cameras, "babylonjs_autoanimateloop");
-            Tools.PrepareNumericUpDown(nupFrom, cameras, "babylonjs_autoanimate_from");
-            Tools.PrepareNumericUpDown(nupTo, cameras, "babylonjs_autoanimate_to", 100.0f);
-        }
-
-        private void butOK_Click(object sender, EventArgs e)
-        {
-            Tools.UpdateCheckBox(chkNoExport, cameras, "babylonjs_noexport");
-            Tools.UpdateCheckBox(chkCollisions, cameras, "babylonjs_checkcollisions");
-            Tools.UpdateCheckBox(chkGravity, cameras, "babylonjs_applygravity");
-
-            Tools.UpdateNumericUpDown(nupSpeed, cameras, "babylonjs_speed");
-            Tools.UpdateNumericUpDown(nupInertia, cameras, "babylonjs_inertia");
-
-            Tools.UpdateVector3Control(ellipsoidControl, cameras, "babylonjs_ellipsoid");
-
-            Tools.UpdateComboBox(cbCameraType, cameras, "babylonjs_type");
-
-            Tools.UpdateCheckBox(chkAutoAnimate, cameras, "babylonjs_autoanimate");
-            Tools.UpdateCheckBox(chkLoop, cameras, "babylonjs_autoanimateloop");
-            Tools.UpdateNumericUpDown(nupFrom, cameras, "babylonjs_autoanimate_from");
-            Tools.UpdateNumericUpDown(nupTo, cameras, "babylonjs_autoanimate_to");
-        }
-
-        private void chkAutoAnimate_CheckedChanged(object sender, EventArgs e)
-        {
-            grpAutoAnimate.Enabled = chkAutoAnimate.Checked;
-        }
-
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+using Autodesk.Max;
+
+namespace Max2Babylon
+{
+    public partial class CameraPropertiesForm : Form
+    {
+        private readonly List<IINode> cameras = new List<IINode>();
+
+        public CameraPropertiesForm()
+        {
+            InitializeComponent();
+        }
+
+        private void CameraPropertiesForm_Load(object sender, EventArgs e)
+        {
+            for (var index = 0; index < Loader.Core.SelNodeCount; index++)
+            {
+                var node = Loader.Core.GetSelNode(index);
+
+                if (node.ObjectRef != null && node.ObjectRef.Eval(0).Obj.SuperClassID == SClass_ID.Camera)
+                {
+                    cameras.Add(node);
+                }
+            }
+
+            Tools.PrepareCheckBox(chkNoExport, cameras, "babylonjs_noexport");
+            Tools.PrepareCheckBox(chkCollisions, cameras, "babylonjs_checkcollisions");
+            Tools.PrepareCheckBox(chkGravity, cameras, "babylonjs_applygravity");
+
+            Tools.PrepareNumericUpDown(nupSpeed, cameras, "babylonjs_speed", 1.0f);
+            Tools.PrepareNumericUpDown(nupInertia, cameras, "babylonjs_inertia", 0.9f);
+
+            Tools.PrepareVector3Control(ellipsoidControl, cameras[0], "babylonjs_ellipsoid", 0.5f, 1.0f, 0.5f);
+
+            Tools.PrepareComboBox(cbCameraType, cameras[0], "babylonjs_type", "FreeCamera");
+
+            Tools.PrepareCheckBox(chkAutoAnimate, cameras, "babylonjs_autoanimate");
+            Tools.PrepareCheckBox(chkLoop, cameras, "babylonjs_autoanimateloop");
+            Tools.PrepareNumericUpDown(nupFrom, cameras, "babylonjs_autoanimate_from");
+            Tools.PrepareNumericUpDown(nupTo, cameras, "babylonjs_autoanimate_to", 100.0f);
+        }
+
+        private void butOK_Click(object sender, EventArgs e)
+        {
+            Tools.UpdateCheckBox(chkNoExport, cameras, "babylonjs_noexport");
+            Tools.UpdateCheckBox(chkCollisions, cameras, "babylonjs_checkcollisions");
+            Tools.UpdateCheckBox(chkGravity, cameras, "babylonjs_applygravity");
+
+            Tools.UpdateNumericUpDown(nupSpeed, cameras, "babylonjs_speed");
+            Tools.UpdateNumericUpDown(nupInertia, cameras, "babylonjs_inertia");
+
+            Tools.UpdateVector3Control(ellipsoidControl, cameras, "babylonjs_ellipsoid");
+
+            Tools.UpdateComboBox(cbCameraType, cameras, "babylonjs_type");
+
+            Tools.UpdateCheckBox(chkAutoAnimate, cameras, "babylonjs_autoanimate");
+            Tools.UpdateCheckBox(chkLoop, cameras, "babylonjs_autoanimateloop");
+            Tools.UpdateNumericUpDown(nupFrom, cameras, "babylonjs_autoanimate_from");
+            Tools.UpdateNumericUpDown(nupTo, cameras, "babylonjs_autoanimate_to");
+        }
+
+        private void chkAutoAnimate_CheckedChanged(object sender, EventArgs e)
+        {
+            grpAutoAnimate.Enabled = chkAutoAnimate.Checked;
+        }
+
+    }
+}

+ 119 - 119
Exporters/3ds Max/Max2Babylon/Forms/CameraPropertiesForm.resx

@@ -1,120 +1,120 @@
-<?xml version="1.0" encoding="utf-8"?>
-<root>
-  <!-- 
-    Microsoft ResX Schema 
-    
-    Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
-    associated with the data types.
-    
-    Example:
-    
-    ... ado.net/XML headers & schema ...
-    <resheader name="resmimetype">text/microsoft-resx</resheader>
-    <resheader name="version">2.0</resheader>
-    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
-    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
-    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
-    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
-    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
-        <value>[base64 mime encoded serialized .NET Framework object]</value>
-    </data>
-    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
-        <comment>This is a comment</comment>
-    </data>
-                
-    There are any number of "resheader" rows that contain simple 
-    name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
-    mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
-    extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
-    read any of the formats listed below.
-    
-    mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
-            : and then encoded with base64 encoding.
-    
-    mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
-            : and then encoded with base64 encoding.
-
-    mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
-            : using a System.ComponentModel.TypeConverter
-            : and then encoded with base64 encoding.
-    -->
-  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
-    <xsd:element name="root" msdata:IsDataSet="true">
-      <xsd:complexType>
-        <xsd:choice maxOccurs="unbounded">
-          <xsd:element name="metadata">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" />
-              </xsd:sequence>
-              <xsd:attribute name="name" use="required" type="xsd:string" />
-              <xsd:attribute name="type" type="xsd:string" />
-              <xsd:attribute name="mimetype" type="xsd:string" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="assembly">
-            <xsd:complexType>
-              <xsd:attribute name="alias" type="xsd:string" />
-              <xsd:attribute name="name" type="xsd:string" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="data">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
-              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
-              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="resheader">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" />
-            </xsd:complexType>
-          </xsd:element>
-        </xsd:choice>
-      </xsd:complexType>
-    </xsd:element>
-  </xsd:schema>
-  <resheader name="resmimetype">
-    <value>text/microsoft-resx</value>
-  </resheader>
-  <resheader name="version">
-    <value>2.0</value>
-  </resheader>
-  <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
 </root>

+ 319 - 319
Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.Designer.cs

@@ -1,320 +1,320 @@
-namespace Max2Babylon
-{
-    partial class ExporterForm
-    {
-        /// <summary>
-        /// Required designer variable.
-        /// </summary>
-        private System.ComponentModel.IContainer components = null;
-
-        /// <summary>
-        /// Clean up any resources being used.
-        /// </summary>
-        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing && (components != null))
-            {
-                components.Dispose();
-            }
-            base.Dispose(disposing);
-        }
-
-        #region Windows Form Designer generated code
-
-        /// <summary>
-        /// Required method for Designer support - do not modify
-        /// the contents of this method with the code editor.
-        /// </summary>
-        private void InitializeComponent()
-        {
-            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ExporterForm));
-            this.butExport = new System.Windows.Forms.Button();
-            this.label1 = new System.Windows.Forms.Label();
-            this.txtFilename = new System.Windows.Forms.TextBox();
-            this.butBrowse = new System.Windows.Forms.Button();
-            this.saveFileDialog = new System.Windows.Forms.SaveFileDialog();
-            this.progressBar = new System.Windows.Forms.ProgressBar();
-            this.treeView = new System.Windows.Forms.TreeView();
-            this.butCancel = new System.Windows.Forms.Button();
-            this.pictureBox2 = new System.Windows.Forms.PictureBox();
-            this.chkManifest = new System.Windows.Forms.CheckBox();
-            this.label2 = new System.Windows.Forms.Label();
-            this.chkCopyTextures = new System.Windows.Forms.CheckBox();
-            this.groupBox1 = new System.Windows.Forms.GroupBox();
-            this.chkBinary = new System.Windows.Forms.CheckBox();
-            this.chkOnlySelected = new System.Windows.Forms.CheckBox();
-            this.chkAutoSave = new System.Windows.Forms.CheckBox();
-            this.chkHidden = new System.Windows.Forms.CheckBox();
-            this.butExportAndRun = new System.Windows.Forms.Button();
-            this.butClose = new System.Windows.Forms.Button();
-            ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();
-            this.groupBox1.SuspendLayout();
-            this.SuspendLayout();
-            // 
-            // butExport
-            // 
-            this.butExport.Anchor = System.Windows.Forms.AnchorStyles.Top;
-            this.butExport.Enabled = false;
-            this.butExport.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butExport.Location = new System.Drawing.Point(211, 153);
-            this.butExport.Name = "butExport";
-            this.butExport.Size = new System.Drawing.Size(197, 27);
-            this.butExport.TabIndex = 0;
-            this.butExport.Text = "Export";
-            this.butExport.UseVisualStyleBackColor = true;
-            this.butExport.Click += new System.EventHandler(this.butExport_Click);
-            // 
-            // label1
-            // 
-            this.label1.AutoSize = true;
-            this.label1.Location = new System.Drawing.Point(6, 17);
-            this.label1.Name = "label1";
-            this.label1.Size = new System.Drawing.Size(52, 13);
-            this.label1.TabIndex = 2;
-            this.label1.Text = "Filename:";
-            // 
-            // txtFilename
-            // 
-            this.txtFilename.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-            this.txtFilename.Location = new System.Drawing.Point(18, 34);
-            this.txtFilename.Name = "txtFilename";
-            this.txtFilename.Size = new System.Drawing.Size(420, 20);
-            this.txtFilename.TabIndex = 3;
-            this.txtFilename.TextChanged += new System.EventHandler(this.txtFilename_TextChanged);
-            // 
-            // butBrowse
-            // 
-            this.butBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
-            this.butBrowse.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butBrowse.Location = new System.Drawing.Point(444, 32);
-            this.butBrowse.Name = "butBrowse";
-            this.butBrowse.Size = new System.Drawing.Size(43, 23);
-            this.butBrowse.TabIndex = 4;
-            this.butBrowse.Text = "...";
-            this.butBrowse.UseVisualStyleBackColor = true;
-            this.butBrowse.Click += new System.EventHandler(this.butBrowse_Click);
-            // 
-            // saveFileDialog
-            // 
-            this.saveFileDialog.DefaultExt = "babylon";
-            this.saveFileDialog.Filter = "Babylon files|*.babylon";
-            this.saveFileDialog.RestoreDirectory = true;
-            // 
-            // progressBar
-            // 
-            this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-            this.progressBar.Location = new System.Drawing.Point(12, 516);
-            this.progressBar.Name = "progressBar";
-            this.progressBar.Size = new System.Drawing.Size(627, 23);
-            this.progressBar.TabIndex = 5;
-            // 
-            // treeView
-            // 
-            this.treeView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
-            | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-            this.treeView.Location = new System.Drawing.Point(12, 186);
-            this.treeView.Name = "treeView";
-            this.treeView.Size = new System.Drawing.Size(799, 324);
-            this.treeView.TabIndex = 6;
-            // 
-            // butCancel
-            // 
-            this.butCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
-            this.butCancel.Enabled = false;
-            this.butCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butCancel.Location = new System.Drawing.Point(645, 516);
-            this.butCancel.Name = "butCancel";
-            this.butCancel.Size = new System.Drawing.Size(80, 23);
-            this.butCancel.TabIndex = 7;
-            this.butCancel.Text = "Cancel";
-            this.butCancel.UseVisualStyleBackColor = true;
-            this.butCancel.Click += new System.EventHandler(this.butCancel_Click);
-            // 
-            // pictureBox2
-            // 
-            this.pictureBox2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
-            this.pictureBox2.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox2.Image")));
-            this.pictureBox2.Location = new System.Drawing.Point(511, 12);
-            this.pictureBox2.Name = "pictureBox2";
-            this.pictureBox2.Size = new System.Drawing.Size(300, 130);
-            this.pictureBox2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
-            this.pictureBox2.TabIndex = 9;
-            this.pictureBox2.TabStop = false;
-            // 
-            // chkManifest
-            // 
-            this.chkManifest.AutoSize = true;
-            this.chkManifest.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.chkManifest.Location = new System.Drawing.Point(18, 104);
-            this.chkManifest.Name = "chkManifest";
-            this.chkManifest.Size = new System.Drawing.Size(112, 17);
-            this.chkManifest.TabIndex = 2;
-            this.chkManifest.Text = "Generate .manifest";
-            this.chkManifest.UseVisualStyleBackColor = true;
-            // 
-            // label2
-            // 
-            this.label2.AutoSize = true;
-            this.label2.Location = new System.Drawing.Point(6, 62);
-            this.label2.Name = "label2";
-            this.label2.Size = new System.Drawing.Size(46, 13);
-            this.label2.TabIndex = 11;
-            this.label2.Text = "Options:";
-            // 
-            // chkCopyTextures
-            // 
-            this.chkCopyTextures.AutoSize = true;
-            this.chkCopyTextures.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.chkCopyTextures.Location = new System.Drawing.Point(18, 81);
-            this.chkCopyTextures.Name = "chkCopyTextures";
-            this.chkCopyTextures.Size = new System.Drawing.Size(132, 17);
-            this.chkCopyTextures.TabIndex = 12;
-            this.chkCopyTextures.Text = "Copy textures to output";
-            this.chkCopyTextures.UseVisualStyleBackColor = true;
-            // 
-            // groupBox1
-            // 
-            this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-            this.groupBox1.Controls.Add(this.chkBinary);
-            this.groupBox1.Controls.Add(this.chkOnlySelected);
-            this.groupBox1.Controls.Add(this.chkAutoSave);
-            this.groupBox1.Controls.Add(this.chkHidden);
-            this.groupBox1.Controls.Add(this.label1);
-            this.groupBox1.Controls.Add(this.chkCopyTextures);
-            this.groupBox1.Controls.Add(this.txtFilename);
-            this.groupBox1.Controls.Add(this.chkManifest);
-            this.groupBox1.Controls.Add(this.butBrowse);
-            this.groupBox1.Controls.Add(this.label2);
-            this.groupBox1.Location = new System.Drawing.Point(12, 6);
-            this.groupBox1.Name = "groupBox1";
-            this.groupBox1.Size = new System.Drawing.Size(493, 136);
-            this.groupBox1.TabIndex = 13;
-            this.groupBox1.TabStop = false;
-            // 
-            // chkBinary
-            // 
-            this.chkBinary.AutoSize = true;
-            this.chkBinary.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.chkBinary.Location = new System.Drawing.Point(320, 104);
-            this.chkBinary.Name = "chkBinary";
-            this.chkBinary.Size = new System.Drawing.Size(135, 17);
-            this.chkBinary.TabIndex = 16;
-            this.chkBinary.Text = "Generate binary version";
-            this.chkBinary.UseVisualStyleBackColor = true;
-            // 
-            // chkOnlySelected
-            // 
-            this.chkOnlySelected.AutoSize = true;
-            this.chkOnlySelected.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.chkOnlySelected.Location = new System.Drawing.Point(320, 81);
-            this.chkOnlySelected.Name = "chkOnlySelected";
-            this.chkOnlySelected.Size = new System.Drawing.Size(118, 17);
-            this.chkOnlySelected.TabIndex = 15;
-            this.chkOnlySelected.Text = "Export only selected";
-            this.chkOnlySelected.UseVisualStyleBackColor = true;
-            // 
-            // chkAutoSave
-            // 
-            this.chkAutoSave.AutoSize = true;
-            this.chkAutoSave.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.chkAutoSave.Location = new System.Drawing.Point(166, 104);
-            this.chkAutoSave.Name = "chkAutoSave";
-            this.chkAutoSave.Size = new System.Drawing.Size(130, 17);
-            this.chkAutoSave.TabIndex = 14;
-            this.chkAutoSave.Text = "Auto save 3ds Max file";
-            this.chkAutoSave.UseVisualStyleBackColor = true;
-            // 
-            // chkHidden
-            // 
-            this.chkHidden.AutoSize = true;
-            this.chkHidden.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.chkHidden.Location = new System.Drawing.Point(166, 81);
-            this.chkHidden.Name = "chkHidden";
-            this.chkHidden.Size = new System.Drawing.Size(125, 17);
-            this.chkHidden.TabIndex = 13;
-            this.chkHidden.Text = "Export hidden objects";
-            this.chkHidden.UseVisualStyleBackColor = true;
-            // 
-            // butExportAndRun
-            // 
-            this.butExportAndRun.Anchor = System.Windows.Forms.AnchorStyles.Top;
-            this.butExportAndRun.Enabled = false;
-            this.butExportAndRun.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butExportAndRun.Location = new System.Drawing.Point(414, 153);
-            this.butExportAndRun.Name = "butExportAndRun";
-            this.butExportAndRun.Size = new System.Drawing.Size(197, 27);
-            this.butExportAndRun.TabIndex = 14;
-            this.butExportAndRun.Text = "Export && Run";
-            this.butExportAndRun.UseVisualStyleBackColor = true;
-            this.butExportAndRun.Click += new System.EventHandler(this.butExportAndRun_Click);
-            // 
-            // butClose
-            // 
-            this.butClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
-            this.butClose.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butClose.Location = new System.Drawing.Point(731, 516);
-            this.butClose.Name = "butClose";
-            this.butClose.Size = new System.Drawing.Size(80, 23);
-            this.butClose.TabIndex = 7;
-            this.butClose.Text = "Close";
-            this.butClose.UseVisualStyleBackColor = true;
-            this.butClose.Click += new System.EventHandler(this.butClose_Click);
-            // 
-            // ExporterForm
-            // 
-            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.ClientSize = new System.Drawing.Size(823, 551);
-            this.Controls.Add(this.butExportAndRun);
-            this.Controls.Add(this.groupBox1);
-            this.Controls.Add(this.pictureBox2);
-            this.Controls.Add(this.butClose);
-            this.Controls.Add(this.butCancel);
-            this.Controls.Add(this.treeView);
-            this.Controls.Add(this.progressBar);
-            this.Controls.Add(this.butExport);
-            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
-            this.MinimumSize = new System.Drawing.Size(750, 400);
-            this.Name = "ExporterForm";
-            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
-            this.Text = "Babylon.js - Export scene to .babylon file";
-            this.Activated += new System.EventHandler(this.ExporterForm_Activated);
-            this.Deactivate += new System.EventHandler(this.ExporterForm_Deactivate);
-            this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ExporterForm_FormClosed);
-            this.Load += new System.EventHandler(this.ExporterForm_Load);
-            ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit();
-            this.groupBox1.ResumeLayout(false);
-            this.groupBox1.PerformLayout();
-            this.ResumeLayout(false);
-            this.PerformLayout();
-
-        }
-
-        #endregion
-
-        private System.Windows.Forms.Button butExport;
-        private System.Windows.Forms.Label label1;
-        private System.Windows.Forms.TextBox txtFilename;
-        private System.Windows.Forms.Button butBrowse;
-        private System.Windows.Forms.SaveFileDialog saveFileDialog;
-        private System.Windows.Forms.ProgressBar progressBar;
-        private System.Windows.Forms.TreeView treeView;
-        private System.Windows.Forms.Button butCancel;
-        private System.Windows.Forms.PictureBox pictureBox2;
-        private System.Windows.Forms.CheckBox chkManifest;
-        private System.Windows.Forms.Label label2;
-        private System.Windows.Forms.CheckBox chkCopyTextures;
-        private System.Windows.Forms.GroupBox groupBox1;
-        private System.Windows.Forms.CheckBox chkHidden;
-        private System.Windows.Forms.CheckBox chkAutoSave;
-        private System.Windows.Forms.Button butExportAndRun;
-        private System.Windows.Forms.CheckBox chkOnlySelected;
-        private System.Windows.Forms.Button butClose;
-        private System.Windows.Forms.CheckBox chkBinary;
-    }
+namespace Max2Babylon
+{
+    partial class ExporterForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ExporterForm));
+            this.butExport = new System.Windows.Forms.Button();
+            this.label1 = new System.Windows.Forms.Label();
+            this.txtFilename = new System.Windows.Forms.TextBox();
+            this.butBrowse = new System.Windows.Forms.Button();
+            this.saveFileDialog = new System.Windows.Forms.SaveFileDialog();
+            this.progressBar = new System.Windows.Forms.ProgressBar();
+            this.treeView = new System.Windows.Forms.TreeView();
+            this.butCancel = new System.Windows.Forms.Button();
+            this.pictureBox2 = new System.Windows.Forms.PictureBox();
+            this.chkManifest = new System.Windows.Forms.CheckBox();
+            this.label2 = new System.Windows.Forms.Label();
+            this.chkCopyTextures = new System.Windows.Forms.CheckBox();
+            this.groupBox1 = new System.Windows.Forms.GroupBox();
+            this.chkBinary = new System.Windows.Forms.CheckBox();
+            this.chkOnlySelected = new System.Windows.Forms.CheckBox();
+            this.chkAutoSave = new System.Windows.Forms.CheckBox();
+            this.chkHidden = new System.Windows.Forms.CheckBox();
+            this.butExportAndRun = new System.Windows.Forms.Button();
+            this.butClose = new System.Windows.Forms.Button();
+            ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();
+            this.groupBox1.SuspendLayout();
+            this.SuspendLayout();
+            // 
+            // butExport
+            // 
+            this.butExport.Anchor = System.Windows.Forms.AnchorStyles.Top;
+            this.butExport.Enabled = false;
+            this.butExport.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.butExport.Location = new System.Drawing.Point(211, 153);
+            this.butExport.Name = "butExport";
+            this.butExport.Size = new System.Drawing.Size(197, 27);
+            this.butExport.TabIndex = 0;
+            this.butExport.Text = "Export";
+            this.butExport.UseVisualStyleBackColor = true;
+            this.butExport.Click += new System.EventHandler(this.butExport_Click);
+            // 
+            // label1
+            // 
+            this.label1.AutoSize = true;
+            this.label1.Location = new System.Drawing.Point(6, 17);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(52, 13);
+            this.label1.TabIndex = 2;
+            this.label1.Text = "Filename:";
+            // 
+            // txtFilename
+            // 
+            this.txtFilename.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.txtFilename.Location = new System.Drawing.Point(18, 34);
+            this.txtFilename.Name = "txtFilename";
+            this.txtFilename.Size = new System.Drawing.Size(420, 20);
+            this.txtFilename.TabIndex = 3;
+            this.txtFilename.TextChanged += new System.EventHandler(this.txtFilename_TextChanged);
+            // 
+            // butBrowse
+            // 
+            this.butBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+            this.butBrowse.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.butBrowse.Location = new System.Drawing.Point(444, 32);
+            this.butBrowse.Name = "butBrowse";
+            this.butBrowse.Size = new System.Drawing.Size(43, 23);
+            this.butBrowse.TabIndex = 4;
+            this.butBrowse.Text = "...";
+            this.butBrowse.UseVisualStyleBackColor = true;
+            this.butBrowse.Click += new System.EventHandler(this.butBrowse_Click);
+            // 
+            // saveFileDialog
+            // 
+            this.saveFileDialog.DefaultExt = "babylon";
+            this.saveFileDialog.Filter = "Babylon files|*.babylon";
+            this.saveFileDialog.RestoreDirectory = true;
+            // 
+            // progressBar
+            // 
+            this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.progressBar.Location = new System.Drawing.Point(12, 516);
+            this.progressBar.Name = "progressBar";
+            this.progressBar.Size = new System.Drawing.Size(627, 23);
+            this.progressBar.TabIndex = 5;
+            // 
+            // treeView
+            // 
+            this.treeView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.treeView.Location = new System.Drawing.Point(12, 186);
+            this.treeView.Name = "treeView";
+            this.treeView.Size = new System.Drawing.Size(799, 324);
+            this.treeView.TabIndex = 6;
+            // 
+            // butCancel
+            // 
+            this.butCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+            this.butCancel.Enabled = false;
+            this.butCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.butCancel.Location = new System.Drawing.Point(645, 516);
+            this.butCancel.Name = "butCancel";
+            this.butCancel.Size = new System.Drawing.Size(80, 23);
+            this.butCancel.TabIndex = 7;
+            this.butCancel.Text = "Cancel";
+            this.butCancel.UseVisualStyleBackColor = true;
+            this.butCancel.Click += new System.EventHandler(this.butCancel_Click);
+            // 
+            // pictureBox2
+            // 
+            this.pictureBox2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+            this.pictureBox2.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox2.Image")));
+            this.pictureBox2.Location = new System.Drawing.Point(511, 12);
+            this.pictureBox2.Name = "pictureBox2";
+            this.pictureBox2.Size = new System.Drawing.Size(300, 130);
+            this.pictureBox2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
+            this.pictureBox2.TabIndex = 9;
+            this.pictureBox2.TabStop = false;
+            // 
+            // chkManifest
+            // 
+            this.chkManifest.AutoSize = true;
+            this.chkManifest.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkManifest.Location = new System.Drawing.Point(18, 104);
+            this.chkManifest.Name = "chkManifest";
+            this.chkManifest.Size = new System.Drawing.Size(112, 17);
+            this.chkManifest.TabIndex = 2;
+            this.chkManifest.Text = "Generate .manifest";
+            this.chkManifest.UseVisualStyleBackColor = true;
+            // 
+            // label2
+            // 
+            this.label2.AutoSize = true;
+            this.label2.Location = new System.Drawing.Point(6, 62);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(46, 13);
+            this.label2.TabIndex = 11;
+            this.label2.Text = "Options:";
+            // 
+            // chkCopyTextures
+            // 
+            this.chkCopyTextures.AutoSize = true;
+            this.chkCopyTextures.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkCopyTextures.Location = new System.Drawing.Point(18, 81);
+            this.chkCopyTextures.Name = "chkCopyTextures";
+            this.chkCopyTextures.Size = new System.Drawing.Size(132, 17);
+            this.chkCopyTextures.TabIndex = 12;
+            this.chkCopyTextures.Text = "Copy textures to output";
+            this.chkCopyTextures.UseVisualStyleBackColor = true;
+            // 
+            // groupBox1
+            // 
+            this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+            this.groupBox1.Controls.Add(this.chkBinary);
+            this.groupBox1.Controls.Add(this.chkOnlySelected);
+            this.groupBox1.Controls.Add(this.chkAutoSave);
+            this.groupBox1.Controls.Add(this.chkHidden);
+            this.groupBox1.Controls.Add(this.label1);
+            this.groupBox1.Controls.Add(this.chkCopyTextures);
+            this.groupBox1.Controls.Add(this.txtFilename);
+            this.groupBox1.Controls.Add(this.chkManifest);
+            this.groupBox1.Controls.Add(this.butBrowse);
+            this.groupBox1.Controls.Add(this.label2);
+            this.groupBox1.Location = new System.Drawing.Point(12, 6);
+            this.groupBox1.Name = "groupBox1";
+            this.groupBox1.Size = new System.Drawing.Size(493, 136);
+            this.groupBox1.TabIndex = 13;
+            this.groupBox1.TabStop = false;
+            // 
+            // chkBinary
+            // 
+            this.chkBinary.AutoSize = true;
+            this.chkBinary.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkBinary.Location = new System.Drawing.Point(320, 104);
+            this.chkBinary.Name = "chkBinary";
+            this.chkBinary.Size = new System.Drawing.Size(135, 17);
+            this.chkBinary.TabIndex = 16;
+            this.chkBinary.Text = "Generate binary version";
+            this.chkBinary.UseVisualStyleBackColor = true;
+            // 
+            // chkOnlySelected
+            // 
+            this.chkOnlySelected.AutoSize = true;
+            this.chkOnlySelected.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkOnlySelected.Location = new System.Drawing.Point(320, 81);
+            this.chkOnlySelected.Name = "chkOnlySelected";
+            this.chkOnlySelected.Size = new System.Drawing.Size(118, 17);
+            this.chkOnlySelected.TabIndex = 15;
+            this.chkOnlySelected.Text = "Export only selected";
+            this.chkOnlySelected.UseVisualStyleBackColor = true;
+            // 
+            // chkAutoSave
+            // 
+            this.chkAutoSave.AutoSize = true;
+            this.chkAutoSave.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkAutoSave.Location = new System.Drawing.Point(166, 104);
+            this.chkAutoSave.Name = "chkAutoSave";
+            this.chkAutoSave.Size = new System.Drawing.Size(130, 17);
+            this.chkAutoSave.TabIndex = 14;
+            this.chkAutoSave.Text = "Auto save 3ds Max file";
+            this.chkAutoSave.UseVisualStyleBackColor = true;
+            // 
+            // chkHidden
+            // 
+            this.chkHidden.AutoSize = true;
+            this.chkHidden.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkHidden.Location = new System.Drawing.Point(166, 81);
+            this.chkHidden.Name = "chkHidden";
+            this.chkHidden.Size = new System.Drawing.Size(125, 17);
+            this.chkHidden.TabIndex = 13;
+            this.chkHidden.Text = "Export hidden objects";
+            this.chkHidden.UseVisualStyleBackColor = true;
+            // 
+            // butExportAndRun
+            // 
+            this.butExportAndRun.Anchor = System.Windows.Forms.AnchorStyles.Top;
+            this.butExportAndRun.Enabled = false;
+            this.butExportAndRun.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.butExportAndRun.Location = new System.Drawing.Point(414, 153);
+            this.butExportAndRun.Name = "butExportAndRun";
+            this.butExportAndRun.Size = new System.Drawing.Size(197, 27);
+            this.butExportAndRun.TabIndex = 14;
+            this.butExportAndRun.Text = "Export && Run";
+            this.butExportAndRun.UseVisualStyleBackColor = true;
+            this.butExportAndRun.Click += new System.EventHandler(this.butExportAndRun_Click);
+            // 
+            // butClose
+            // 
+            this.butClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+            this.butClose.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.butClose.Location = new System.Drawing.Point(731, 516);
+            this.butClose.Name = "butClose";
+            this.butClose.Size = new System.Drawing.Size(80, 23);
+            this.butClose.TabIndex = 7;
+            this.butClose.Text = "Close";
+            this.butClose.UseVisualStyleBackColor = true;
+            this.butClose.Click += new System.EventHandler(this.butClose_Click);
+            // 
+            // ExporterForm
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(823, 551);
+            this.Controls.Add(this.butExportAndRun);
+            this.Controls.Add(this.groupBox1);
+            this.Controls.Add(this.pictureBox2);
+            this.Controls.Add(this.butClose);
+            this.Controls.Add(this.butCancel);
+            this.Controls.Add(this.treeView);
+            this.Controls.Add(this.progressBar);
+            this.Controls.Add(this.butExport);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
+            this.MinimumSize = new System.Drawing.Size(750, 400);
+            this.Name = "ExporterForm";
+            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+            this.Text = "Babylon.js - Export scene to .babylon file";
+            this.Activated += new System.EventHandler(this.ExporterForm_Activated);
+            this.Deactivate += new System.EventHandler(this.ExporterForm_Deactivate);
+            this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.ExporterForm_FormClosed);
+            this.Load += new System.EventHandler(this.ExporterForm_Load);
+            ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit();
+            this.groupBox1.ResumeLayout(false);
+            this.groupBox1.PerformLayout();
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Button butExport;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.TextBox txtFilename;
+        private System.Windows.Forms.Button butBrowse;
+        private System.Windows.Forms.SaveFileDialog saveFileDialog;
+        private System.Windows.Forms.ProgressBar progressBar;
+        private System.Windows.Forms.TreeView treeView;
+        private System.Windows.Forms.Button butCancel;
+        private System.Windows.Forms.PictureBox pictureBox2;
+        private System.Windows.Forms.CheckBox chkManifest;
+        private System.Windows.Forms.Label label2;
+        private System.Windows.Forms.CheckBox chkCopyTextures;
+        private System.Windows.Forms.GroupBox groupBox1;
+        private System.Windows.Forms.CheckBox chkHidden;
+        private System.Windows.Forms.CheckBox chkAutoSave;
+        private System.Windows.Forms.Button butExportAndRun;
+        private System.Windows.Forms.CheckBox chkOnlySelected;
+        private System.Windows.Forms.Button butClose;
+        private System.Windows.Forms.CheckBox chkBinary;
+    }
 }

+ 229 - 229
Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.cs

@@ -1,229 +1,229 @@
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-
-using Color = System.Drawing.Color;
-
-namespace Max2Babylon
-{
-    public partial class ExporterForm : Form
-    {
-        private readonly BabylonExportActionItem babylonExportAction;
-        private BabylonExporter exporter;
-
-        TreeNode currentNode;
-        int currentRank;
-
-        public ExporterForm(BabylonExportActionItem babylonExportAction)
-        {
-            InitializeComponent();
-
-            this.babylonExportAction = babylonExportAction;
-        }
-
-        private void ExporterForm_Load(object sender, EventArgs e)
-        {
-            txtFilename.Text = Loader.Core.RootNode.GetLocalData();
-            Tools.PrepareCheckBox(chkManifest, Loader.Core.RootNode, "babylonjs_generatemanifest");
-            Tools.PrepareCheckBox(chkCopyTextures, Loader.Core.RootNode, "babylonjs_copytextures", 1);
-            Tools.PrepareCheckBox(chkHidden, Loader.Core.RootNode, "babylonjs_exporthidden");
-            Tools.PrepareCheckBox(chkAutoSave, Loader.Core.RootNode, "babylonjs_autosave", 1);
-            Tools.PrepareCheckBox(chkOnlySelected, Loader.Core.RootNode, "babylonjs_onlySelected");
-            Tools.PrepareCheckBox(chkBinary, Loader.Core.RootNode, "babylonjs_binary"); 
-        }
-
-        private void butBrowse_Click(object sender, EventArgs e)
-        {
-            if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
-            {
-                txtFilename.Text = saveFileDialog.FileName;
-            }
-        }
-
-        private async void butExport_Click(object sender, EventArgs e)
-        {
-            await DoExport();
-        }
-
-        private async Task<bool> DoExport()
-        {
-            Tools.UpdateCheckBox(chkManifest, Loader.Core.RootNode, "babylonjs_generatemanifest");
-            Tools.UpdateCheckBox(chkCopyTextures, Loader.Core.RootNode, "babylonjs_copytextures");
-            Tools.UpdateCheckBox(chkHidden, Loader.Core.RootNode, "babylonjs_exporthidden");
-            Tools.UpdateCheckBox(chkAutoSave, Loader.Core.RootNode, "babylonjs_autosave");
-            Tools.UpdateCheckBox(chkOnlySelected, Loader.Core.RootNode, "babylonjs_onlySelected");
-            Tools.UpdateCheckBox(chkBinary, Loader.Core.RootNode, "babylonjs_binary");
-
-            Loader.Core.RootNode.SetLocalData(txtFilename.Text);
-
-            exporter = new BabylonExporter();
-
-            treeView.Nodes.Clear();
-
-            exporter.OnImportProgressChanged += progress =>
-            {
-                progressBar.Value = progress;
-                Application.DoEvents();
-            };
-
-            exporter.OnWarning += (warning, rank) =>
-            {
-                try
-                {
-                    currentNode = CreateTreeNode(rank, warning, Color.DarkOrange);
-                    currentNode.EnsureVisible();
-                }
-                catch
-                {
-                }
-                Application.DoEvents();
-            };
-
-            exporter.OnError += (error, rank) =>
-            {
-                try
-                {
-                    currentNode = CreateTreeNode(rank, error, Color.Red);
-                    currentNode.EnsureVisible();
-                }
-                catch
-                {
-                }
-                Application.DoEvents();
-            };
-
-            exporter.OnMessage += (message, color, rank, emphasis) =>
-            {
-                try
-                {
-                    currentNode = CreateTreeNode(rank, message, color);
-
-                    if (emphasis)
-                    {
-                        currentNode.EnsureVisible();
-                    }
-                }
-                catch
-                {
-                }
-                Application.DoEvents();
-            };
-
-            butExport.Enabled = false;
-            butExportAndRun.Enabled = false;
-            butCancel.Enabled = true;
-
-            bool success = true;
-            try
-            {
-                exporter.AutoSave3dsMaxFile = chkAutoSave.Checked;
-                exporter.ExportHiddenObjects = chkHidden.Checked;
-                exporter.CopyTexturesToOutput = chkCopyTextures.Checked;
-                await exporter.ExportAsync(txtFilename.Text, chkManifest.Checked, chkOnlySelected.Checked, chkBinary.Checked, this);
-            }
-            catch (OperationCanceledException)
-            {
-                progressBar.Value = 0;
-                success = false;
-            }
-            catch (Exception ex)
-            {
-                currentNode = CreateTreeNode(0, "Exportation cancelled: " + ex.Message, Color.Red);
-
-                currentNode.EnsureVisible();
-                progressBar.Value = 0;
-                success = false;
-            }
-
-            butCancel.Enabled = false;
-            butExport.Enabled = true;
-            butExportAndRun.Enabled = WebServer.IsSupported;
-
-            BringToFront();
-
-            return success;
-        }
-
-        private TreeNode CreateTreeNode(int rank, string text, Color color)
-        {
-            TreeNode newNode = null;
-
-            Invoke(new Action(() =>
-            {
-                newNode = new TreeNode(text) {ForeColor = color};
-                if (rank == 0)
-                {
-                    treeView.Nodes.Add(newNode);
-                }
-                else if (rank == currentRank + 1)
-                {
-                    currentNode.Nodes.Add(newNode);
-                }
-                else
-                {
-                    var parentNode = currentNode;
-                    while (currentRank != rank - 1)
-                    {
-                        parentNode = parentNode.Parent;
-                        currentRank--;
-                    }
-                    parentNode.Nodes.Add(newNode);
-                }
-
-                currentRank = rank;
-            }));
-
-            return newNode;
-        }
-
-        private void ExporterForm_FormClosed(object sender, FormClosedEventArgs e)
-        {
-            if (exporter != null)
-            {
-                exporter.IsCancelled = true;                
-            }
-            babylonExportAction.Close();
-        }
-
-        private void txtFilename_TextChanged(object sender, EventArgs e)
-        {
-            butExport.Enabled = !string.IsNullOrEmpty(txtFilename.Text.Trim());
-            butExportAndRun.Enabled = butExport.Enabled && WebServer.IsSupported;
-        }
-
-        private void butCancel_Click(object sender, EventArgs e)
-        {
-            exporter.IsCancelled = true;
-        }
-
-        private void ExporterForm_Activated(object sender, EventArgs e)
-        {
-            Loader.Global.DisableAccelerators();
-        }
-
-        private void ExporterForm_Deactivate(object sender, EventArgs e)
-        {
-            Loader.Global.EnableAccelerators();
-        }
-
-        private async void butExportAndRun_Click(object sender, EventArgs e)
-        {
-            if (await DoExport())
-            {
-                WebServer.SceneFilename = Path.GetFileName(txtFilename.Text);
-                WebServer.SceneFolder = Path.GetDirectoryName(txtFilename.Text);
-
-                Process.Start("http://localhost:" + WebServer.Port);
-
-                WindowState = FormWindowState.Minimized;
-            }
-        }
-
-        private void butClose_Click(object sender, EventArgs e)
-        {
-            Close();
-        }
-    }
-}
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+using Color = System.Drawing.Color;
+
+namespace Max2Babylon
+{
+    public partial class ExporterForm : Form
+    {
+        private readonly BabylonExportActionItem babylonExportAction;
+        private BabylonExporter exporter;
+
+        TreeNode currentNode;
+        int currentRank;
+
+        public ExporterForm(BabylonExportActionItem babylonExportAction)
+        {
+            InitializeComponent();
+
+            this.babylonExportAction = babylonExportAction;
+        }
+
+        private void ExporterForm_Load(object sender, EventArgs e)
+        {
+            txtFilename.Text = Loader.Core.RootNode.GetLocalData();
+            Tools.PrepareCheckBox(chkManifest, Loader.Core.RootNode, "babylonjs_generatemanifest");
+            Tools.PrepareCheckBox(chkCopyTextures, Loader.Core.RootNode, "babylonjs_copytextures", 1);
+            Tools.PrepareCheckBox(chkHidden, Loader.Core.RootNode, "babylonjs_exporthidden");
+            Tools.PrepareCheckBox(chkAutoSave, Loader.Core.RootNode, "babylonjs_autosave", 1);
+            Tools.PrepareCheckBox(chkOnlySelected, Loader.Core.RootNode, "babylonjs_onlySelected");
+            Tools.PrepareCheckBox(chkBinary, Loader.Core.RootNode, "babylonjs_binary"); 
+        }
+
+        private void butBrowse_Click(object sender, EventArgs e)
+        {
+            if (saveFileDialog.ShowDialog(this) == DialogResult.OK)
+            {
+                txtFilename.Text = saveFileDialog.FileName;
+            }
+        }
+
+        private async void butExport_Click(object sender, EventArgs e)
+        {
+            await DoExport();
+        }
+
+        private async Task<bool> DoExport()
+        {
+            Tools.UpdateCheckBox(chkManifest, Loader.Core.RootNode, "babylonjs_generatemanifest");
+            Tools.UpdateCheckBox(chkCopyTextures, Loader.Core.RootNode, "babylonjs_copytextures");
+            Tools.UpdateCheckBox(chkHidden, Loader.Core.RootNode, "babylonjs_exporthidden");
+            Tools.UpdateCheckBox(chkAutoSave, Loader.Core.RootNode, "babylonjs_autosave");
+            Tools.UpdateCheckBox(chkOnlySelected, Loader.Core.RootNode, "babylonjs_onlySelected");
+            Tools.UpdateCheckBox(chkBinary, Loader.Core.RootNode, "babylonjs_binary");
+
+            Loader.Core.RootNode.SetLocalData(txtFilename.Text);
+
+            exporter = new BabylonExporter();
+
+            treeView.Nodes.Clear();
+
+            exporter.OnImportProgressChanged += progress =>
+            {
+                progressBar.Value = progress;
+                Application.DoEvents();
+            };
+
+            exporter.OnWarning += (warning, rank) =>
+            {
+                try
+                {
+                    currentNode = CreateTreeNode(rank, warning, Color.DarkOrange);
+                    currentNode.EnsureVisible();
+                }
+                catch
+                {
+                }
+                Application.DoEvents();
+            };
+
+            exporter.OnError += (error, rank) =>
+            {
+                try
+                {
+                    currentNode = CreateTreeNode(rank, error, Color.Red);
+                    currentNode.EnsureVisible();
+                }
+                catch
+                {
+                }
+                Application.DoEvents();
+            };
+
+            exporter.OnMessage += (message, color, rank, emphasis) =>
+            {
+                try
+                {
+                    currentNode = CreateTreeNode(rank, message, color);
+
+                    if (emphasis)
+                    {
+                        currentNode.EnsureVisible();
+                    }
+                }
+                catch
+                {
+                }
+                Application.DoEvents();
+            };
+
+            butExport.Enabled = false;
+            butExportAndRun.Enabled = false;
+            butCancel.Enabled = true;
+
+            bool success = true;
+            try
+            {
+                exporter.AutoSave3dsMaxFile = chkAutoSave.Checked;
+                exporter.ExportHiddenObjects = chkHidden.Checked;
+                exporter.CopyTexturesToOutput = chkCopyTextures.Checked;
+                await exporter.ExportAsync(txtFilename.Text, chkManifest.Checked, chkOnlySelected.Checked, chkBinary.Checked, this);
+            }
+            catch (OperationCanceledException)
+            {
+                progressBar.Value = 0;
+                success = false;
+            }
+            catch (Exception ex)
+            {
+                currentNode = CreateTreeNode(0, "Exportation cancelled: " + ex.Message, Color.Red);
+
+                currentNode.EnsureVisible();
+                progressBar.Value = 0;
+                success = false;
+            }
+
+            butCancel.Enabled = false;
+            butExport.Enabled = true;
+            butExportAndRun.Enabled = WebServer.IsSupported;
+
+            BringToFront();
+
+            return success;
+        }
+
+        private TreeNode CreateTreeNode(int rank, string text, Color color)
+        {
+            TreeNode newNode = null;
+
+            Invoke(new Action(() =>
+            {
+                newNode = new TreeNode(text) {ForeColor = color};
+                if (rank == 0)
+                {
+                    treeView.Nodes.Add(newNode);
+                }
+                else if (rank == currentRank + 1)
+                {
+                    currentNode.Nodes.Add(newNode);
+                }
+                else
+                {
+                    var parentNode = currentNode;
+                    while (currentRank != rank - 1)
+                    {
+                        parentNode = parentNode.Parent;
+                        currentRank--;
+                    }
+                    parentNode.Nodes.Add(newNode);
+                }
+
+                currentRank = rank;
+            }));
+
+            return newNode;
+        }
+
+        private void ExporterForm_FormClosed(object sender, FormClosedEventArgs e)
+        {
+            if (exporter != null)
+            {
+                exporter.IsCancelled = true;                
+            }
+            babylonExportAction.Close();
+        }
+
+        private void txtFilename_TextChanged(object sender, EventArgs e)
+        {
+            butExport.Enabled = !string.IsNullOrEmpty(txtFilename.Text.Trim());
+            butExportAndRun.Enabled = butExport.Enabled && WebServer.IsSupported;
+        }
+
+        private void butCancel_Click(object sender, EventArgs e)
+        {
+            exporter.IsCancelled = true;
+        }
+
+        private void ExporterForm_Activated(object sender, EventArgs e)
+        {
+            Loader.Global.DisableAccelerators();
+        }
+
+        private void ExporterForm_Deactivate(object sender, EventArgs e)
+        {
+            Loader.Global.EnableAccelerators();
+        }
+
+        private async void butExportAndRun_Click(object sender, EventArgs e)
+        {
+            if (await DoExport())
+            {
+                WebServer.SceneFilename = Path.GetFileName(txtFilename.Text);
+                WebServer.SceneFolder = Path.GetDirectoryName(txtFilename.Text);
+
+                Process.Start("http://localhost:" + WebServer.Port);
+
+                WindowState = FormWindowState.Minimized;
+            }
+        }
+
+        private void butClose_Click(object sender, EventArgs e)
+        {
+            Close();
+        }
+    }
+}

+ 320 - 320
Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.resx

@@ -1,321 +1,321 @@
-<?xml version="1.0" encoding="utf-8"?>
-<root>
-  <!-- 
-    Microsoft ResX Schema 
-    
-    Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
-    associated with the data types.
-    
-    Example:
-    
-    ... ado.net/XML headers & schema ...
-    <resheader name="resmimetype">text/microsoft-resx</resheader>
-    <resheader name="version">2.0</resheader>
-    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
-    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
-    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
-    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
-    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
-        <value>[base64 mime encoded serialized .NET Framework object]</value>
-    </data>
-    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
-        <comment>This is a comment</comment>
-    </data>
-                
-    There are any number of "resheader" rows that contain simple 
-    name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
-    mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
-    extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
-    read any of the formats listed below.
-    
-    mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
-            : and then encoded with base64 encoding.
-    
-    mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
-            : and then encoded with base64 encoding.
-
-    mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
-            : using a System.ComponentModel.TypeConverter
-            : and then encoded with base64 encoding.
-    -->
-  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
-    <xsd:element name="root" msdata:IsDataSet="true">
-      <xsd:complexType>
-        <xsd:choice maxOccurs="unbounded">
-          <xsd:element name="metadata">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" />
-              </xsd:sequence>
-              <xsd:attribute name="name" use="required" type="xsd:string" />
-              <xsd:attribute name="type" type="xsd:string" />
-              <xsd:attribute name="mimetype" type="xsd:string" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="assembly">
-            <xsd:complexType>
-              <xsd:attribute name="alias" type="xsd:string" />
-              <xsd:attribute name="name" type="xsd:string" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="data">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
-              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
-              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="resheader">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" />
-            </xsd:complexType>
-          </xsd:element>
-        </xsd:choice>
-      </xsd:complexType>
-    </xsd:element>
-  </xsd:schema>
-  <resheader name="resmimetype">
-    <value>text/microsoft-resx</value>
-  </resheader>
-  <resheader name="version">
-    <value>2.0</value>
-  </resheader>
-  <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <metadata name="saveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>17, 17</value>
-  </metadata>
-  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
-  <data name="pictureBox2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        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
-        QmCC
-</value>
-  </data>
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="saveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <data name="pictureBox2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        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
+        QmCC
+</value>
+  </data>
 </root>

+ 419 - 405
Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.Designer.cs

@@ -1,406 +1,420 @@
-namespace Max2Babylon
-{
-    partial class LightPropertiesForm
-    {
-        /// <summary>
-        /// Required designer variable.
-        /// </summary>
-        private System.ComponentModel.IContainer components = null;
-
-        /// <summary>
-        /// Clean up any resources being used.
-        /// </summary>
-        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing && (components != null))
-            {
-                components.Dispose();
-            }
-            base.Dispose(disposing);
-        }
-
-        #region Windows Form Designer generated code
-
-        /// <summary>
-        /// Required method for Designer support - do not modify
-        /// the contents of this method with the code editor.
-        /// </summary>
-        private void InitializeComponent()
-        {
-            this.butOK = new System.Windows.Forms.Button();
-            this.butCancel = new System.Windows.Forms.Button();
-            this.groupBox3 = new System.Windows.Forms.GroupBox();
-            this.grpAutoAnimate = new System.Windows.Forms.GroupBox();
-            this.chkLoop = new System.Windows.Forms.CheckBox();
-            this.nupTo = new System.Windows.Forms.NumericUpDown();
-            this.label4 = new System.Windows.Forms.Label();
-            this.nupFrom = new System.Windows.Forms.NumericUpDown();
-            this.label5 = new System.Windows.Forms.Label();
-            this.chkAutoAnimate = new System.Windows.Forms.CheckBox();
-            this.groupBox4 = new System.Windows.Forms.GroupBox();
-            this.chkNoExport = new System.Windows.Forms.CheckBox();
-            this.groupBox1 = new System.Windows.Forms.GroupBox();
-            this.grpBlurInfo = new System.Windows.Forms.GroupBox();
-            this.nupBlurBoxOffset = new System.Windows.Forms.NumericUpDown();
-            this.label3 = new System.Windows.Forms.Label();
-            this.label6 = new System.Windows.Forms.Label();
-            this.nupBlurScale = new System.Windows.Forms.NumericUpDown();
-            this.cbCameraType = new System.Windows.Forms.ComboBox();
-            this.label2 = new System.Windows.Forms.Label();
-            this.nupBias = new System.Windows.Forms.NumericUpDown();
-            this.label1 = new System.Windows.Forms.Label();
-            this.groupBox3.SuspendLayout();
-            this.grpAutoAnimate.SuspendLayout();
-            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).BeginInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).BeginInit();
-            this.groupBox4.SuspendLayout();
-            this.groupBox1.SuspendLayout();
-            this.grpBlurInfo.SuspendLayout();
-            ((System.ComponentModel.ISupportInitialize)(this.nupBlurBoxOffset)).BeginInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupBlurScale)).BeginInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupBias)).BeginInit();
-            this.SuspendLayout();
-            // 
-            // butOK
-            // 
-            this.butOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
-            this.butOK.DialogResult = System.Windows.Forms.DialogResult.OK;
-            this.butOK.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butOK.Location = new System.Drawing.Point(93, 454);
-            this.butOK.Name = "butOK";
-            this.butOK.Size = new System.Drawing.Size(75, 23);
-            this.butOK.TabIndex = 1;
-            this.butOK.Text = "OK";
-            this.butOK.UseVisualStyleBackColor = true;
-            this.butOK.Click += new System.EventHandler(this.butOK_Click);
-            // 
-            // butCancel
-            // 
-            this.butCancel.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
-            this.butCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
-            this.butCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butCancel.Location = new System.Drawing.Point(174, 454);
-            this.butCancel.Name = "butCancel";
-            this.butCancel.Size = new System.Drawing.Size(75, 23);
-            this.butCancel.TabIndex = 2;
-            this.butCancel.Text = "Cancel";
-            this.butCancel.UseVisualStyleBackColor = true;
-            // 
-            // groupBox3
-            // 
-            this.groupBox3.Controls.Add(this.grpAutoAnimate);
-            this.groupBox3.Controls.Add(this.chkAutoAnimate);
-            this.groupBox3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.groupBox3.Location = new System.Drawing.Point(12, 284);
-            this.groupBox3.Name = "groupBox3";
-            this.groupBox3.Size = new System.Drawing.Size(319, 156);
-            this.groupBox3.TabIndex = 5;
-            this.groupBox3.TabStop = false;
-            this.groupBox3.Text = "Animations";
-            // 
-            // grpAutoAnimate
-            // 
-            this.grpAutoAnimate.Controls.Add(this.chkLoop);
-            this.grpAutoAnimate.Controls.Add(this.nupTo);
-            this.grpAutoAnimate.Controls.Add(this.label4);
-            this.grpAutoAnimate.Controls.Add(this.nupFrom);
-            this.grpAutoAnimate.Controls.Add(this.label5);
-            this.grpAutoAnimate.Enabled = false;
-            this.grpAutoAnimate.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.grpAutoAnimate.Location = new System.Drawing.Point(21, 51);
-            this.grpAutoAnimate.Name = "grpAutoAnimate";
-            this.grpAutoAnimate.Size = new System.Drawing.Size(292, 99);
-            this.grpAutoAnimate.TabIndex = 3;
-            this.grpAutoAnimate.TabStop = false;
-            // 
-            // chkLoop
-            // 
-            this.chkLoop.AutoSize = true;
-            this.chkLoop.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.chkLoop.Location = new System.Drawing.Point(9, 66);
-            this.chkLoop.Name = "chkLoop";
-            this.chkLoop.Size = new System.Drawing.Size(47, 17);
-            this.chkLoop.TabIndex = 5;
-            this.chkLoop.Text = "Loop";
-            this.chkLoop.ThreeState = true;
-            this.chkLoop.UseVisualStyleBackColor = true;
-            // 
-            // nupTo
-            // 
-            this.nupTo.Location = new System.Drawing.Point(47, 40);
-            this.nupTo.Maximum = new decimal(new int[] {
-            1000,
-            0,
-            0,
-            0});
-            this.nupTo.Name = "nupTo";
-            this.nupTo.Size = new System.Drawing.Size(120, 20);
-            this.nupTo.TabIndex = 3;
-            // 
-            // label4
-            // 
-            this.label4.AutoSize = true;
-            this.label4.Location = new System.Drawing.Point(6, 42);
-            this.label4.Name = "label4";
-            this.label4.Size = new System.Drawing.Size(23, 13);
-            this.label4.TabIndex = 4;
-            this.label4.Text = "To:";
-            // 
-            // nupFrom
-            // 
-            this.nupFrom.Location = new System.Drawing.Point(47, 14);
-            this.nupFrom.Maximum = new decimal(new int[] {
-            1000,
-            0,
-            0,
-            0});
-            this.nupFrom.Name = "nupFrom";
-            this.nupFrom.Size = new System.Drawing.Size(120, 20);
-            this.nupFrom.TabIndex = 1;
-            // 
-            // label5
-            // 
-            this.label5.AutoSize = true;
-            this.label5.Location = new System.Drawing.Point(6, 16);
-            this.label5.Name = "label5";
-            this.label5.Size = new System.Drawing.Size(33, 13);
-            this.label5.TabIndex = 2;
-            this.label5.Text = "From:";
-            // 
-            // chkAutoAnimate
-            // 
-            this.chkAutoAnimate.AutoSize = true;
-            this.chkAutoAnimate.Location = new System.Drawing.Point(21, 28);
-            this.chkAutoAnimate.Name = "chkAutoAnimate";
-            this.chkAutoAnimate.Size = new System.Drawing.Size(88, 17);
-            this.chkAutoAnimate.TabIndex = 0;
-            this.chkAutoAnimate.Text = "Auto animate";
-            this.chkAutoAnimate.ThreeState = true;
-            this.chkAutoAnimate.UseVisualStyleBackColor = true;
-            this.chkAutoAnimate.CheckedChanged += new System.EventHandler(this.chkAutoAnimate_CheckedChanged);
-            // 
-            // groupBox4
-            // 
-            this.groupBox4.Controls.Add(this.chkNoExport);
-            this.groupBox4.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.groupBox4.Location = new System.Drawing.Point(12, 12);
-            this.groupBox4.Name = "groupBox4";
-            this.groupBox4.Size = new System.Drawing.Size(319, 59);
-            this.groupBox4.TabIndex = 7;
-            this.groupBox4.TabStop = false;
-            this.groupBox4.Text = "Misc.";
-            // 
-            // chkNoExport
-            // 
-            this.chkNoExport.AutoSize = true;
-            this.chkNoExport.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.chkNoExport.Location = new System.Drawing.Point(21, 28);
-            this.chkNoExport.Name = "chkNoExport";
-            this.chkNoExport.Size = new System.Drawing.Size(87, 17);
-            this.chkNoExport.TabIndex = 4;
-            this.chkNoExport.Text = "Do not export";
-            this.chkNoExport.ThreeState = true;
-            this.chkNoExport.UseVisualStyleBackColor = true;
-            // 
-            // groupBox1
-            // 
-            this.groupBox1.Controls.Add(this.grpBlurInfo);
-            this.groupBox1.Controls.Add(this.nupBias);
-            this.groupBox1.Controls.Add(this.label6);
-            this.groupBox1.Controls.Add(this.label1);
-            this.groupBox1.Controls.Add(this.cbCameraType);
-            this.groupBox1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.groupBox1.Location = new System.Drawing.Point(12, 77);
-            this.groupBox1.Name = "groupBox1";
-            this.groupBox1.Size = new System.Drawing.Size(319, 201);
-            this.groupBox1.TabIndex = 6;
-            this.groupBox1.TabStop = false;
-            this.groupBox1.Text = "Shadows";
-            // 
-            // grpBlurInfo
-            // 
-            this.grpBlurInfo.Controls.Add(this.nupBlurBoxOffset);
-            this.grpBlurInfo.Controls.Add(this.label3);
-            this.grpBlurInfo.Controls.Add(this.nupBlurScale);
-            this.grpBlurInfo.Controls.Add(this.label2);
-            this.grpBlurInfo.Enabled = false;
-            this.grpBlurInfo.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.grpBlurInfo.Location = new System.Drawing.Point(21, 108);
-            this.grpBlurInfo.Name = "grpBlurInfo";
-            this.grpBlurInfo.Size = new System.Drawing.Size(292, 87);
-            this.grpBlurInfo.TabIndex = 13;
-            this.grpBlurInfo.TabStop = false;
-            this.grpBlurInfo.Text = "Blur info";
-            // 
-            // nupBlurBoxOffset
-            // 
-            this.nupBlurBoxOffset.Location = new System.Drawing.Point(89, 50);
-            this.nupBlurBoxOffset.Maximum = new decimal(new int[] {
-            3,
-            0,
-            0,
-            0});
-            this.nupBlurBoxOffset.Minimum = new decimal(new int[] {
-            1,
-            0,
-            0,
-            0});
-            this.nupBlurBoxOffset.Name = "nupBlurBoxOffset";
-            this.nupBlurBoxOffset.Size = new System.Drawing.Size(120, 20);
-            this.nupBlurBoxOffset.TabIndex = 13;
-            this.nupBlurBoxOffset.Value = new decimal(new int[] {
-            1,
-            0,
-            0,
-            0});
-            // 
-            // label3
-            // 
-            this.label3.AutoSize = true;
-            this.label3.Location = new System.Drawing.Point(6, 52);
-            this.label3.Name = "label3";
-            this.label3.Size = new System.Drawing.Size(77, 13);
-            this.label3.TabIndex = 14;
-            this.label3.Text = "Blur box offset:";
-            // 
-            // label6
-            // 
-            this.label6.AutoSize = true;
-            this.label6.Location = new System.Drawing.Point(21, 55);
-            this.label6.Name = "label6";
-            this.label6.Size = new System.Drawing.Size(34, 13);
-            this.label6.TabIndex = 8;
-            this.label6.Text = "Type:";
-            // 
-            // nupBlurScale
-            // 
-            this.nupBlurScale.Location = new System.Drawing.Point(89, 24);
-            this.nupBlurScale.Maximum = new decimal(new int[] {
-            10,
-            0,
-            0,
-            0});
-            this.nupBlurScale.Minimum = new decimal(new int[] {
-            1,
-            0,
-            0,
-            0});
-            this.nupBlurScale.Name = "nupBlurScale";
-            this.nupBlurScale.Size = new System.Drawing.Size(120, 20);
-            this.nupBlurScale.TabIndex = 11;
-            this.nupBlurScale.Value = new decimal(new int[] {
-            1,
-            0,
-            0,
-            0});
-            // 
-            // cbCameraType
-            // 
-            this.cbCameraType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
-            this.cbCameraType.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.cbCameraType.FormattingEnabled = true;
-            this.cbCameraType.Items.AddRange(new object[] {
-            "Hard shadows",
-            "Poisson Sampling",
-            "Variance",
-            "Blurred Variance"});
-            this.cbCameraType.Location = new System.Drawing.Point(24, 71);
-            this.cbCameraType.Name = "cbCameraType";
-            this.cbCameraType.Size = new System.Drawing.Size(289, 21);
-            this.cbCameraType.TabIndex = 7;
-            this.cbCameraType.SelectedIndexChanged += new System.EventHandler(this.cbCameraType_SelectedIndexChanged);
-            // 
-            // label2
-            // 
-            this.label2.AutoSize = true;
-            this.label2.Location = new System.Drawing.Point(6, 26);
-            this.label2.Name = "label2";
-            this.label2.Size = new System.Drawing.Size(56, 13);
-            this.label2.TabIndex = 12;
-            this.label2.Text = "Blur scale:";
-            // 
-            // nupBias
-            // 
-            this.nupBias.DecimalPlaces = 5;
-            this.nupBias.Location = new System.Drawing.Point(57, 26);
-            this.nupBias.Maximum = new decimal(new int[] {
-            1,
-            0,
-            0,
-            0});
-            this.nupBias.Name = "nupBias";
-            this.nupBias.Size = new System.Drawing.Size(120, 20);
-            this.nupBias.TabIndex = 9;
-            // 
-            // label1
-            // 
-            this.label1.AutoSize = true;
-            this.label1.Location = new System.Drawing.Point(21, 28);
-            this.label1.Name = "label1";
-            this.label1.Size = new System.Drawing.Size(30, 13);
-            this.label1.TabIndex = 10;
-            this.label1.Text = "Bias:";
-            // 
-            // LightPropertiesForm
-            // 
-            this.AcceptButton = this.butOK;
-            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.CancelButton = this.butCancel;
-            this.ClientSize = new System.Drawing.Size(343, 489);
-            this.Controls.Add(this.groupBox1);
-            this.Controls.Add(this.groupBox4);
-            this.Controls.Add(this.groupBox3);
-            this.Controls.Add(this.butCancel);
-            this.Controls.Add(this.butOK);
-            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
-            this.Name = "LightPropertiesForm";
-            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
-            this.Text = "Babylon.js - Light Properties";
-            this.Load += new System.EventHandler(this.LightPropertiesForm_Load);
-            this.groupBox3.ResumeLayout(false);
-            this.groupBox3.PerformLayout();
-            this.grpAutoAnimate.ResumeLayout(false);
-            this.grpAutoAnimate.PerformLayout();
-            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).EndInit();
-            this.groupBox4.ResumeLayout(false);
-            this.groupBox4.PerformLayout();
-            this.groupBox1.ResumeLayout(false);
-            this.groupBox1.PerformLayout();
-            this.grpBlurInfo.ResumeLayout(false);
-            this.grpBlurInfo.PerformLayout();
-            ((System.ComponentModel.ISupportInitialize)(this.nupBlurBoxOffset)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupBlurScale)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupBias)).EndInit();
-            this.ResumeLayout(false);
-
-        }
-
-        #endregion
-
-        private System.Windows.Forms.Button butOK;
-        private System.Windows.Forms.Button butCancel;
-        private System.Windows.Forms.GroupBox groupBox3;
-        private System.Windows.Forms.GroupBox grpAutoAnimate;
-        private System.Windows.Forms.CheckBox chkLoop;
-        private System.Windows.Forms.NumericUpDown nupTo;
-        private System.Windows.Forms.Label label4;
-        private System.Windows.Forms.NumericUpDown nupFrom;
-        private System.Windows.Forms.Label label5;
-        private System.Windows.Forms.CheckBox chkAutoAnimate;
-        private System.Windows.Forms.GroupBox groupBox4;
-        private System.Windows.Forms.CheckBox chkNoExport;
-        private System.Windows.Forms.GroupBox groupBox1;
-        private System.Windows.Forms.Label label6;
-        private System.Windows.Forms.ComboBox cbCameraType;
-        private System.Windows.Forms.NumericUpDown nupBlurScale;
-        private System.Windows.Forms.Label label2;
-        private System.Windows.Forms.NumericUpDown nupBias;
-        private System.Windows.Forms.Label label1;
-        private System.Windows.Forms.GroupBox grpBlurInfo;
-        private System.Windows.Forms.NumericUpDown nupBlurBoxOffset;
-        private System.Windows.Forms.Label label3;
-    }
+namespace Max2Babylon
+{
+    partial class LightPropertiesForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.butOK = new System.Windows.Forms.Button();
+            this.butCancel = new System.Windows.Forms.Button();
+            this.groupBox3 = new System.Windows.Forms.GroupBox();
+            this.grpAutoAnimate = new System.Windows.Forms.GroupBox();
+            this.chkLoop = new System.Windows.Forms.CheckBox();
+            this.nupTo = new System.Windows.Forms.NumericUpDown();
+            this.label4 = new System.Windows.Forms.Label();
+            this.nupFrom = new System.Windows.Forms.NumericUpDown();
+            this.label5 = new System.Windows.Forms.Label();
+            this.chkAutoAnimate = new System.Windows.Forms.CheckBox();
+            this.groupBox4 = new System.Windows.Forms.GroupBox();
+            this.chkNoExport = new System.Windows.Forms.CheckBox();
+            this.groupBox1 = new System.Windows.Forms.GroupBox();
+            this.ckForceBackFaces = new System.Windows.Forms.CheckBox();
+            this.grpBlurInfo = new System.Windows.Forms.GroupBox();
+            this.nupBlurBoxOffset = new System.Windows.Forms.NumericUpDown();
+            this.label3 = new System.Windows.Forms.Label();
+            this.nupBlurScale = new System.Windows.Forms.NumericUpDown();
+            this.label2 = new System.Windows.Forms.Label();
+            this.nupBias = new System.Windows.Forms.NumericUpDown();
+            this.label6 = new System.Windows.Forms.Label();
+            this.label1 = new System.Windows.Forms.Label();
+            this.cbCameraType = new System.Windows.Forms.ComboBox();
+            this.groupBox3.SuspendLayout();
+            this.grpAutoAnimate.SuspendLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).BeginInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).BeginInit();
+            this.groupBox4.SuspendLayout();
+            this.groupBox1.SuspendLayout();
+            this.grpBlurInfo.SuspendLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupBlurBoxOffset)).BeginInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupBlurScale)).BeginInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupBias)).BeginInit();
+            this.SuspendLayout();
+            // 
+            // butOK
+            // 
+            this.butOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
+            this.butOK.DialogResult = System.Windows.Forms.DialogResult.OK;
+            this.butOK.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.butOK.Location = new System.Drawing.Point(93, 484);
+            this.butOK.Name = "butOK";
+            this.butOK.Size = new System.Drawing.Size(75, 23);
+            this.butOK.TabIndex = 1;
+            this.butOK.Text = "OK";
+            this.butOK.UseVisualStyleBackColor = true;
+            this.butOK.Click += new System.EventHandler(this.butOK_Click);
+            // 
+            // butCancel
+            // 
+            this.butCancel.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
+            this.butCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.butCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.butCancel.Location = new System.Drawing.Point(174, 484);
+            this.butCancel.Name = "butCancel";
+            this.butCancel.Size = new System.Drawing.Size(75, 23);
+            this.butCancel.TabIndex = 2;
+            this.butCancel.Text = "Cancel";
+            this.butCancel.UseVisualStyleBackColor = true;
+            // 
+            // groupBox3
+            // 
+            this.groupBox3.Controls.Add(this.grpAutoAnimate);
+            this.groupBox3.Controls.Add(this.chkAutoAnimate);
+            this.groupBox3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.groupBox3.Location = new System.Drawing.Point(12, 319);
+            this.groupBox3.Name = "groupBox3";
+            this.groupBox3.Size = new System.Drawing.Size(319, 156);
+            this.groupBox3.TabIndex = 5;
+            this.groupBox3.TabStop = false;
+            this.groupBox3.Text = "Animations";
+            // 
+            // grpAutoAnimate
+            // 
+            this.grpAutoAnimate.Controls.Add(this.chkLoop);
+            this.grpAutoAnimate.Controls.Add(this.nupTo);
+            this.grpAutoAnimate.Controls.Add(this.label4);
+            this.grpAutoAnimate.Controls.Add(this.nupFrom);
+            this.grpAutoAnimate.Controls.Add(this.label5);
+            this.grpAutoAnimate.Enabled = false;
+            this.grpAutoAnimate.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.grpAutoAnimate.Location = new System.Drawing.Point(21, 51);
+            this.grpAutoAnimate.Name = "grpAutoAnimate";
+            this.grpAutoAnimate.Size = new System.Drawing.Size(292, 99);
+            this.grpAutoAnimate.TabIndex = 3;
+            this.grpAutoAnimate.TabStop = false;
+            // 
+            // chkLoop
+            // 
+            this.chkLoop.AutoSize = true;
+            this.chkLoop.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkLoop.Location = new System.Drawing.Point(9, 66);
+            this.chkLoop.Name = "chkLoop";
+            this.chkLoop.Size = new System.Drawing.Size(47, 17);
+            this.chkLoop.TabIndex = 5;
+            this.chkLoop.Text = "Loop";
+            this.chkLoop.ThreeState = true;
+            this.chkLoop.UseVisualStyleBackColor = true;
+            // 
+            // nupTo
+            // 
+            this.nupTo.Location = new System.Drawing.Point(47, 40);
+            this.nupTo.Maximum = new decimal(new int[] {
+            100000,
+            0,
+            0,
+            0});
+            this.nupTo.Name = "nupTo";
+            this.nupTo.Size = new System.Drawing.Size(120, 20);
+            this.nupTo.TabIndex = 3;
+            // 
+            // label4
+            // 
+            this.label4.AutoSize = true;
+            this.label4.Location = new System.Drawing.Point(6, 42);
+            this.label4.Name = "label4";
+            this.label4.Size = new System.Drawing.Size(23, 13);
+            this.label4.TabIndex = 4;
+            this.label4.Text = "To:";
+            // 
+            // nupFrom
+            // 
+            this.nupFrom.Location = new System.Drawing.Point(47, 14);
+            this.nupFrom.Maximum = new decimal(new int[] {
+            100000,
+            0,
+            0,
+            0});
+            this.nupFrom.Name = "nupFrom";
+            this.nupFrom.Size = new System.Drawing.Size(120, 20);
+            this.nupFrom.TabIndex = 1;
+            // 
+            // label5
+            // 
+            this.label5.AutoSize = true;
+            this.label5.Location = new System.Drawing.Point(6, 16);
+            this.label5.Name = "label5";
+            this.label5.Size = new System.Drawing.Size(33, 13);
+            this.label5.TabIndex = 2;
+            this.label5.Text = "From:";
+            // 
+            // chkAutoAnimate
+            // 
+            this.chkAutoAnimate.AutoSize = true;
+            this.chkAutoAnimate.Location = new System.Drawing.Point(21, 28);
+            this.chkAutoAnimate.Name = "chkAutoAnimate";
+            this.chkAutoAnimate.Size = new System.Drawing.Size(88, 17);
+            this.chkAutoAnimate.TabIndex = 0;
+            this.chkAutoAnimate.Text = "Auto animate";
+            this.chkAutoAnimate.ThreeState = true;
+            this.chkAutoAnimate.UseVisualStyleBackColor = true;
+            this.chkAutoAnimate.CheckedChanged += new System.EventHandler(this.chkAutoAnimate_CheckedChanged);
+            // 
+            // groupBox4
+            // 
+            this.groupBox4.Controls.Add(this.chkNoExport);
+            this.groupBox4.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.groupBox4.Location = new System.Drawing.Point(12, 12);
+            this.groupBox4.Name = "groupBox4";
+            this.groupBox4.Size = new System.Drawing.Size(319, 59);
+            this.groupBox4.TabIndex = 7;
+            this.groupBox4.TabStop = false;
+            this.groupBox4.Text = "Misc.";
+            // 
+            // chkNoExport
+            // 
+            this.chkNoExport.AutoSize = true;
+            this.chkNoExport.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkNoExport.Location = new System.Drawing.Point(21, 28);
+            this.chkNoExport.Name = "chkNoExport";
+            this.chkNoExport.Size = new System.Drawing.Size(87, 17);
+            this.chkNoExport.TabIndex = 4;
+            this.chkNoExport.Text = "Do not export";
+            this.chkNoExport.ThreeState = true;
+            this.chkNoExport.UseVisualStyleBackColor = true;
+            // 
+            // groupBox1
+            // 
+            this.groupBox1.Controls.Add(this.ckForceBackFaces);
+            this.groupBox1.Controls.Add(this.grpBlurInfo);
+            this.groupBox1.Controls.Add(this.nupBias);
+            this.groupBox1.Controls.Add(this.label6);
+            this.groupBox1.Controls.Add(this.label1);
+            this.groupBox1.Controls.Add(this.cbCameraType);
+            this.groupBox1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.groupBox1.Location = new System.Drawing.Point(12, 77);
+            this.groupBox1.Name = "groupBox1";
+            this.groupBox1.Size = new System.Drawing.Size(319, 236);
+            this.groupBox1.TabIndex = 6;
+            this.groupBox1.TabStop = false;
+            this.groupBox1.Text = "Shadows";
+            // 
+            // ckForceBackFaces
+            // 
+            this.ckForceBackFaces.AutoSize = true;
+            this.ckForceBackFaces.Location = new System.Drawing.Point(24, 61);
+            this.ckForceBackFaces.Name = "ckForceBackFaces";
+            this.ckForceBackFaces.Size = new System.Drawing.Size(135, 17);
+            this.ckForceBackFaces.TabIndex = 14;
+            this.ckForceBackFaces.Text = "Force Back Faces only";
+            this.ckForceBackFaces.ThreeState = true;
+            this.ckForceBackFaces.UseVisualStyleBackColor = true;
+            // 
+            // grpBlurInfo
+            // 
+            this.grpBlurInfo.Controls.Add(this.nupBlurBoxOffset);
+            this.grpBlurInfo.Controls.Add(this.label3);
+            this.grpBlurInfo.Controls.Add(this.nupBlurScale);
+            this.grpBlurInfo.Controls.Add(this.label2);
+            this.grpBlurInfo.Enabled = false;
+            this.grpBlurInfo.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.grpBlurInfo.Location = new System.Drawing.Point(18, 144);
+            this.grpBlurInfo.Name = "grpBlurInfo";
+            this.grpBlurInfo.Size = new System.Drawing.Size(292, 87);
+            this.grpBlurInfo.TabIndex = 13;
+            this.grpBlurInfo.TabStop = false;
+            this.grpBlurInfo.Text = "Blur info";
+            // 
+            // nupBlurBoxOffset
+            // 
+            this.nupBlurBoxOffset.Location = new System.Drawing.Point(89, 50);
+            this.nupBlurBoxOffset.Maximum = new decimal(new int[] {
+            3,
+            0,
+            0,
+            0});
+            this.nupBlurBoxOffset.Minimum = new decimal(new int[] {
+            1,
+            0,
+            0,
+            0});
+            this.nupBlurBoxOffset.Name = "nupBlurBoxOffset";
+            this.nupBlurBoxOffset.Size = new System.Drawing.Size(120, 20);
+            this.nupBlurBoxOffset.TabIndex = 13;
+            this.nupBlurBoxOffset.Value = new decimal(new int[] {
+            1,
+            0,
+            0,
+            0});
+            // 
+            // label3
+            // 
+            this.label3.AutoSize = true;
+            this.label3.Location = new System.Drawing.Point(6, 52);
+            this.label3.Name = "label3";
+            this.label3.Size = new System.Drawing.Size(77, 13);
+            this.label3.TabIndex = 14;
+            this.label3.Text = "Blur box offset:";
+            // 
+            // nupBlurScale
+            // 
+            this.nupBlurScale.Location = new System.Drawing.Point(89, 24);
+            this.nupBlurScale.Maximum = new decimal(new int[] {
+            10,
+            0,
+            0,
+            0});
+            this.nupBlurScale.Minimum = new decimal(new int[] {
+            1,
+            0,
+            0,
+            0});
+            this.nupBlurScale.Name = "nupBlurScale";
+            this.nupBlurScale.Size = new System.Drawing.Size(120, 20);
+            this.nupBlurScale.TabIndex = 11;
+            this.nupBlurScale.Value = new decimal(new int[] {
+            1,
+            0,
+            0,
+            0});
+            // 
+            // label2
+            // 
+            this.label2.AutoSize = true;
+            this.label2.Location = new System.Drawing.Point(6, 26);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(56, 13);
+            this.label2.TabIndex = 12;
+            this.label2.Text = "Blur scale:";
+            // 
+            // nupBias
+            // 
+            this.nupBias.DecimalPlaces = 5;
+            this.nupBias.Location = new System.Drawing.Point(57, 26);
+            this.nupBias.Maximum = new decimal(new int[] {
+            1,
+            0,
+            0,
+            0});
+            this.nupBias.Name = "nupBias";
+            this.nupBias.Size = new System.Drawing.Size(120, 20);
+            this.nupBias.TabIndex = 9;
+            // 
+            // label6
+            // 
+            this.label6.AutoSize = true;
+            this.label6.Location = new System.Drawing.Point(18, 92);
+            this.label6.Name = "label6";
+            this.label6.Size = new System.Drawing.Size(34, 13);
+            this.label6.TabIndex = 8;
+            this.label6.Text = "Type:";
+            // 
+            // label1
+            // 
+            this.label1.AutoSize = true;
+            this.label1.Location = new System.Drawing.Point(21, 28);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(30, 13);
+            this.label1.TabIndex = 10;
+            this.label1.Text = "Bias:";
+            // 
+            // cbCameraType
+            // 
+            this.cbCameraType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.cbCameraType.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.cbCameraType.FormattingEnabled = true;
+            this.cbCameraType.Items.AddRange(new object[] {
+            "Hard shadows",
+            "Poisson Sampling",
+            "Variance",
+            "Blurred Variance"});
+            this.cbCameraType.Location = new System.Drawing.Point(21, 108);
+            this.cbCameraType.Name = "cbCameraType";
+            this.cbCameraType.Size = new System.Drawing.Size(289, 21);
+            this.cbCameraType.TabIndex = 7;
+            this.cbCameraType.SelectedIndexChanged += new System.EventHandler(this.cbCameraType_SelectedIndexChanged);
+            // 
+            // LightPropertiesForm
+            // 
+            this.AcceptButton = this.butOK;
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.CancelButton = this.butCancel;
+            this.ClientSize = new System.Drawing.Size(343, 519);
+            this.Controls.Add(this.groupBox1);
+            this.Controls.Add(this.groupBox4);
+            this.Controls.Add(this.groupBox3);
+            this.Controls.Add(this.butCancel);
+            this.Controls.Add(this.butOK);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
+            this.Name = "LightPropertiesForm";
+            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+            this.Text = "Babylon.js - Light Properties";
+            this.Load += new System.EventHandler(this.LightPropertiesForm_Load);
+            this.groupBox3.ResumeLayout(false);
+            this.groupBox3.PerformLayout();
+            this.grpAutoAnimate.ResumeLayout(false);
+            this.grpAutoAnimate.PerformLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).EndInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).EndInit();
+            this.groupBox4.ResumeLayout(false);
+            this.groupBox4.PerformLayout();
+            this.groupBox1.ResumeLayout(false);
+            this.groupBox1.PerformLayout();
+            this.grpBlurInfo.ResumeLayout(false);
+            this.grpBlurInfo.PerformLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupBlurBoxOffset)).EndInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupBlurScale)).EndInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupBias)).EndInit();
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Button butOK;
+        private System.Windows.Forms.Button butCancel;
+        private System.Windows.Forms.GroupBox groupBox3;
+        private System.Windows.Forms.GroupBox grpAutoAnimate;
+        private System.Windows.Forms.CheckBox chkLoop;
+        private System.Windows.Forms.NumericUpDown nupTo;
+        private System.Windows.Forms.Label label4;
+        private System.Windows.Forms.NumericUpDown nupFrom;
+        private System.Windows.Forms.Label label5;
+        private System.Windows.Forms.CheckBox chkAutoAnimate;
+        private System.Windows.Forms.GroupBox groupBox4;
+        private System.Windows.Forms.CheckBox chkNoExport;
+        private System.Windows.Forms.GroupBox groupBox1;
+        private System.Windows.Forms.Label label6;
+        private System.Windows.Forms.ComboBox cbCameraType;
+        private System.Windows.Forms.NumericUpDown nupBlurScale;
+        private System.Windows.Forms.Label label2;
+        private System.Windows.Forms.NumericUpDown nupBias;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.GroupBox grpBlurInfo;
+        private System.Windows.Forms.NumericUpDown nupBlurBoxOffset;
+        private System.Windows.Forms.Label label3;
+        private System.Windows.Forms.CheckBox ckForceBackFaces;
+    }
 }

+ 67 - 65
Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.cs

@@ -1,65 +1,67 @@
-using System;
-using System.Collections.Generic;
-using System.Windows.Forms;
-using Autodesk.Max;
-
-namespace Max2Babylon
-{
-    public partial class LightPropertiesForm : Form
-    {
-        private readonly List<IINode> lights = new List<IINode>();
-
-        public LightPropertiesForm()
-        {
-            InitializeComponent();
-        }
-
-        private void LightPropertiesForm_Load(object sender, EventArgs e)
-        {
-            for (var index = 0; index < Loader.Core.SelNodeCount; index++)
-            {
-                var node = Loader.Core.GetSelNode(index);
-
-                if (node.ObjectRef != null && node.ObjectRef.Eval(0).Obj.SuperClassID == SClass_ID.Light)
-                {
-                    lights.Add(node);
-                }
-            }
-
-            Tools.PrepareCheckBox(chkNoExport, lights, "babylonjs_noexport");
-            Tools.PrepareCheckBox(chkAutoAnimate, lights, "babylonjs_autoanimate");
-            Tools.PrepareCheckBox(chkLoop, lights, "babylonjs_autoanimateloop");
-            Tools.PrepareNumericUpDown(nupFrom, lights, "babylonjs_autoanimate_from");
-            Tools.PrepareNumericUpDown(nupTo, lights, "babylonjs_autoanimate_to", 100.0f);
-
-            Tools.PrepareNumericUpDown(nupBias, lights, "babylonjs_shadows_bias", 0.00005f);
-            Tools.PrepareNumericUpDown(nupBlurScale, lights, "babylonjs_shadows_blurScale", 2);
-            Tools.PrepareNumericUpDown(nupBlurBoxOffset, lights, "babylonjs_shadows_blurBoxOffset", 1);
-            Tools.PrepareComboBox(cbCameraType, lights[0], "babylonjs_shadows_type", "Blurred Variance");
-        }
-
-        private void butOK_Click(object sender, EventArgs e)
-        {
-            Tools.UpdateCheckBox(chkNoExport, lights, "babylonjs_noexport");
-            Tools.UpdateCheckBox(chkAutoAnimate, lights, "babylonjs_autoanimate");
-            Tools.UpdateCheckBox(chkLoop, lights, "babylonjs_autoanimateloop");
-            Tools.UpdateNumericUpDown(nupFrom, lights, "babylonjs_autoanimate_from");
-            Tools.UpdateNumericUpDown(nupTo, lights, "babylonjs_autoanimate_to");
-
-            Tools.UpdateNumericUpDown(nupBias, lights, "babylonjs_shadows_bias");
-            Tools.UpdateNumericUpDown(nupBlurScale, lights, "babylonjs_shadows_blurScale");
-            Tools.UpdateNumericUpDown(nupBlurBoxOffset, lights, "babylonjs_shadows_blurBoxOffset");
-            Tools.UpdateComboBox(cbCameraType, lights, "babylonjs_shadows_type");
-        }
-
-        private void chkAutoAnimate_CheckedChanged(object sender, EventArgs e)
-        {
-            grpAutoAnimate.Enabled = chkAutoAnimate.Checked;
-        }
-
-        private void cbCameraType_SelectedIndexChanged(object sender, EventArgs e)
-        {
-            grpBlurInfo.Enabled = (cbCameraType.SelectedIndex == 3);
-        }
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+using Autodesk.Max;
+
+namespace Max2Babylon
+{
+    public partial class LightPropertiesForm : Form
+    {
+        private readonly List<IINode> lights = new List<IINode>();
+
+        public LightPropertiesForm()
+        {
+            InitializeComponent();
+        }
+
+        private void LightPropertiesForm_Load(object sender, EventArgs e)
+        {
+            for (var index = 0; index < Loader.Core.SelNodeCount; index++)
+            {
+                var node = Loader.Core.GetSelNode(index);
+
+                if (node.ObjectRef != null && node.ObjectRef.Eval(0).Obj.SuperClassID == SClass_ID.Light)
+                {
+                    lights.Add(node);
+                }
+            }
+
+            Tools.PrepareCheckBox(chkNoExport, lights, "babylonjs_noexport");
+            Tools.PrepareCheckBox(chkAutoAnimate, lights, "babylonjs_autoanimate");
+            Tools.PrepareCheckBox(chkLoop, lights, "babylonjs_autoanimateloop");
+            Tools.PrepareCheckBox(ckForceBackFaces, lights, "babylonjs_forcebackfaces");
+            Tools.PrepareNumericUpDown(nupFrom, lights, "babylonjs_autoanimate_from");
+            Tools.PrepareNumericUpDown(nupTo, lights, "babylonjs_autoanimate_to", 100.0f);
+
+            Tools.PrepareNumericUpDown(nupBias, lights, "babylonjs_shadows_bias", 0.00005f);
+            Tools.PrepareNumericUpDown(nupBlurScale, lights, "babylonjs_shadows_blurScale", 2);
+            Tools.PrepareNumericUpDown(nupBlurBoxOffset, lights, "babylonjs_shadows_blurBoxOffset", 1);
+            Tools.PrepareComboBox(cbCameraType, lights[0], "babylonjs_shadows_type", "Blurred Variance");
+        }
+
+        private void butOK_Click(object sender, EventArgs e)
+        {
+            Tools.UpdateCheckBox(chkNoExport, lights, "babylonjs_noexport");
+            Tools.UpdateCheckBox(chkAutoAnimate, lights, "babylonjs_autoanimate");
+            Tools.UpdateCheckBox(chkLoop, lights, "babylonjs_autoanimateloop");
+            Tools.UpdateCheckBox(ckForceBackFaces, lights, "babylonjs_forcebackfaces");
+            Tools.UpdateNumericUpDown(nupFrom, lights, "babylonjs_autoanimate_from");
+            Tools.UpdateNumericUpDown(nupTo, lights, "babylonjs_autoanimate_to");
+
+            Tools.UpdateNumericUpDown(nupBias, lights, "babylonjs_shadows_bias");
+            Tools.UpdateNumericUpDown(nupBlurScale, lights, "babylonjs_shadows_blurScale");
+            Tools.UpdateNumericUpDown(nupBlurBoxOffset, lights, "babylonjs_shadows_blurBoxOffset");
+            Tools.UpdateComboBox(cbCameraType, lights, "babylonjs_shadows_type");
+        }
+
+        private void chkAutoAnimate_CheckedChanged(object sender, EventArgs e)
+        {
+            grpAutoAnimate.Enabled = chkAutoAnimate.Checked;
+        }
+
+        private void cbCameraType_SelectedIndexChanged(object sender, EventArgs e)
+        {
+            grpBlurInfo.Enabled = (cbCameraType.SelectedIndex == 3);
+        }
+    }
+}

+ 119 - 119
Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.resx

@@ -1,120 +1,120 @@
-<?xml version="1.0" encoding="utf-8"?>
-<root>
-  <!-- 
-    Microsoft ResX Schema 
-    
-    Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
-    associated with the data types.
-    
-    Example:
-    
-    ... ado.net/XML headers & schema ...
-    <resheader name="resmimetype">text/microsoft-resx</resheader>
-    <resheader name="version">2.0</resheader>
-    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
-    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
-    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
-    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
-    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
-        <value>[base64 mime encoded serialized .NET Framework object]</value>
-    </data>
-    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
-        <comment>This is a comment</comment>
-    </data>
-                
-    There are any number of "resheader" rows that contain simple 
-    name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
-    mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
-    extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
-    read any of the formats listed below.
-    
-    mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
-            : and then encoded with base64 encoding.
-    
-    mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
-            : and then encoded with base64 encoding.
-
-    mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
-            : using a System.ComponentModel.TypeConverter
-            : and then encoded with base64 encoding.
-    -->
-  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
-    <xsd:element name="root" msdata:IsDataSet="true">
-      <xsd:complexType>
-        <xsd:choice maxOccurs="unbounded">
-          <xsd:element name="metadata">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" />
-              </xsd:sequence>
-              <xsd:attribute name="name" use="required" type="xsd:string" />
-              <xsd:attribute name="type" type="xsd:string" />
-              <xsd:attribute name="mimetype" type="xsd:string" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="assembly">
-            <xsd:complexType>
-              <xsd:attribute name="alias" type="xsd:string" />
-              <xsd:attribute name="name" type="xsd:string" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="data">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
-              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
-              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="resheader">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" />
-            </xsd:complexType>
-          </xsd:element>
-        </xsd:choice>
-      </xsd:complexType>
-    </xsd:element>
-  </xsd:schema>
-  <resheader name="resmimetype">
-    <value>text/microsoft-resx</value>
-  </resheader>
-  <resheader name="version">
-    <value>2.0</value>
-  </resheader>
-  <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
 </root>

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 943 - 943
Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.Designer.cs


+ 127 - 122
Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.cs

@@ -1,122 +1,127 @@
-using System;
-using System.Collections.Generic;
-using System.Windows.Forms;
-using Autodesk.Max;
-
-namespace Max2Babylon
-{
-    public partial class ObjectPropertiesForm : Form
-    {
-        private readonly List<IINode> objects = new List<IINode>();
-
-        public ObjectPropertiesForm()
-        {
-            InitializeComponent();
-        }
-
-        private void butOK_Click(object sender, EventArgs e)
-        {
-            Tools.UpdateCheckBox(chkNoExport, objects, "babylonjs_noexport");
-            Tools.UpdateCheckBox(chkCollisions, objects, "babylonjs_checkcollisions");
-            Tools.UpdateCheckBox(chkPickable, objects, "babylonjs_checkpickable");
-            Tools.UpdateCheckBox(chkOptimize, objects, "babylonjs_optimizevertices");
-            Tools.UpdateCheckBox(chkShowBoundingBox, objects, "babylonjs_showboundingbox");
-            Tools.UpdateCheckBox(chkShowSubMeshesBoundingBox, objects, "babylonjs_showsubmeshesboundingbox");
-
-            Tools.UpdateCheckBox(chkAutoAnimate, objects, "babylonjs_autoanimate");
-            Tools.UpdateCheckBox(chkLoop, objects, "babylonjs_autoanimateloop");
-            Tools.UpdateNumericUpDown(nupFrom, objects, "babylonjs_autoanimate_from");
-            Tools.UpdateNumericUpDown(nupTo, objects, "babylonjs_autoanimate_to");
-
-            Tools.UpdateNumericUpDown(nupAlphaIndex, objects, "babylonjs_alphaindex");
-            Tools.UpdateNumericUpDown(nupMass, objects, "babylonjs_mass");
-            Tools.UpdateNumericUpDown(nupFriction, objects, "babylonjs_friction");
-            Tools.UpdateNumericUpDown(nupRestitution, objects, "babylonjs_restitution");
-            Tools.UpdateComboBox(cbImpostor, objects, "babylonjs_impostor");
-
-            Tools.UpdateCheckBox(chkAutoPlay, objects, "babylonjs_sound_autoplay");
-            Tools.UpdateCheckBox(chkLoop, objects, "babylonjs_sound_loop");
-            Tools.UpdateNumericUpDown(nupVolume, objects, "babylonjs_sound_volume");
-            Tools.UpdateNumericUpDown(nupPlaybackRate, objects, "babylonjs_sound_playbackrate");
-
-            Tools.UpdateComboBox(cbDistanceModel, objects, "babylonjs_sound_distancemodel");
-            Tools.UpdateNumericUpDown(nupMaxDistance, objects, "babylonjs_sound_maxdistance");
-            Tools.UpdateNumericUpDown(nupRolloff, objects, "babylonjs_sound_rolloff");
-            Tools.UpdateNumericUpDown(nupRefDistance, objects, "babylonjs_sound_refdistance");
-
-            Tools.UpdateCheckBox(chkDirectional, objects, "babylonjs_sound_directional");
-            Tools.UpdateNumericUpDown(nupConeInnerAngle, objects, "babylonjs_sound_coneinnerangle");
-            Tools.UpdateNumericUpDown(nupConeOuterAngle, objects, "babylonjs_sound_coneouterangle");
-            Tools.UpdateNumericUpDown(nupConeOuterGain, objects, "babylonjs_sound_coneoutergain");
-
-            Tools.UpdateTextBox(txtSound, objects, "babylonjs_sound_filename");
-        }
-
-        private void ObjectPropertiesForm_Load(object sender, EventArgs e)
-        {
-            for (var index = 0; index < Loader.Core.SelNodeCount; index++)
-            {
-                var node = Loader.Core.GetSelNode(index);
-
-                if (node.ObjectRef != null && node.ObjectRef.Eval(0).Obj.SuperClassID == SClass_ID.Geomobject)
-                {
-                    objects.Add(node);
-                }
-            }
-
-            Tools.PrepareCheckBox(chkNoExport, objects, "babylonjs_noexport");
-            Tools.PrepareCheckBox(chkCollisions, objects, "babylonjs_checkcollisions");
-            Tools.PrepareCheckBox(chkPickable, objects, "babylonjs_checkpickable");
-            Tools.PrepareCheckBox(chkOptimize, objects, "babylonjs_optimizevertices");
-            Tools.PrepareCheckBox(chkShowBoundingBox, objects, "babylonjs_showboundingbox");
-            Tools.PrepareCheckBox(chkShowSubMeshesBoundingBox, objects, "babylonjs_showsubmeshesboundingbox");
-
-            Tools.PrepareCheckBox(chkAutoAnimate, objects, "babylonjs_autoanimate", 1);
-            Tools.PrepareCheckBox(chkLoop, objects, "babylonjs_autoanimateloop", 1);
-            Tools.PrepareNumericUpDown(nupFrom, objects, "babylonjs_autoanimate_from");
-            Tools.PrepareNumericUpDown(nupTo, objects, "babylonjs_autoanimate_to", 100.0f);
-            Tools.PrepareNumericUpDown(nupAlphaIndex, objects, "babylonjs_alphaindex", 1000);
-
-            Tools.PrepareNumericUpDown(nupMass, objects, "babylonjs_mass");
-            Tools.PrepareNumericUpDown(nupFriction, objects, "babylonjs_friction", 0.2f);
-            Tools.PrepareNumericUpDown(nupRestitution, objects, "babylonjs_restitution", 0.2f);
-
-            Tools.PrepareComboBox(cbImpostor, objects[0], "babylonjs_impostor", "None");
-
-            Tools.PrepareCheckBox(chkAutoPlay, objects, "babylonjs_sound_autoplay", 1);
-            Tools.PrepareCheckBox(chkLoop, objects, "babylonjs_sound_loop", 1);
-            Tools.PrepareNumericUpDown(nupVolume, objects, "babylonjs_sound_volume", 1.0f);
-            Tools.PrepareNumericUpDown(nupPlaybackRate, objects, "babylonjs_sound_playbackrate", 1.0f);
-
-            Tools.PrepareComboBox(cbDistanceModel, objects[0], "babylonjs_sound_distancemodel", "linear");
-            Tools.PrepareNumericUpDown(nupMaxDistance, objects, "babylonjs_sound_maxdistance", 100.0f);
-            Tools.PrepareNumericUpDown(nupRolloff, objects, "babylonjs_sound_rolloff", 1.0f);
-            Tools.PrepareNumericUpDown(nupRefDistance, objects, "babylonjs_sound_refdistance", 1.0f);
-
-            Tools.PrepareCheckBox(chkDirectional, objects, "babylonjs_sound_directional", 0);
-            Tools.PrepareNumericUpDown(nupConeInnerAngle, objects, "babylonjs_sound_coneinnerangle", 360.00f);
-            Tools.PrepareNumericUpDown(nupConeOuterAngle, objects, "babylonjs_sound_coneouterangle", 360.00f);
-            Tools.PrepareNumericUpDown(nupConeOuterGain, objects, "babylonjs_sound_coneoutergain", 1.0f);
-
-            Tools.PrepareTextBox(txtSound, objects[0], "babylonjs_sound_filename");
-        }
-
-        private void chkAutoAnimate_CheckedChanged(object sender, EventArgs e)
-        {
-            grpAutoAnimate.Enabled = chkAutoAnimate.Checked;
-        }
-
-        private void chkDirectional_CheckedChanged(object sender, EventArgs e)
-        {
-            grpDirectional.Enabled = chkDirectional.Checked;
-        }
-
-        private void cmdFileBrowse_Click(object sender, EventArgs e)
-        {
-            if (ofdOpenSound.ShowDialog() == DialogResult.OK)
-            {
-                txtSound.Text = ofdOpenSound.FileName;
-            }
-        }
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+using Autodesk.Max;
+
+namespace Max2Babylon
+{
+    public partial class ObjectPropertiesForm : Form
+    {
+        private readonly List<IINode> objects = new List<IINode>();
+
+        public ObjectPropertiesForm()
+        {
+            InitializeComponent();
+        }
+
+        private void butOK_Click(object sender, EventArgs e)
+        {
+            Tools.UpdateCheckBox(chkNoExport, objects, "babylonjs_noexport");
+            Tools.UpdateCheckBox(chkCollisions, objects, "babylonjs_checkcollisions");
+            Tools.UpdateCheckBox(chkPickable, objects, "babylonjs_checkpickable");
+            Tools.UpdateCheckBox(chkOptimize, objects, "babylonjs_optimizevertices");
+            Tools.UpdateCheckBox(chkShowBoundingBox, objects, "babylonjs_showboundingbox");
+            Tools.UpdateCheckBox(chkShowSubMeshesBoundingBox, objects, "babylonjs_showsubmeshesboundingbox");
+
+            Tools.UpdateCheckBox(chkAutoAnimate, objects, "babylonjs_autoanimate");
+            Tools.UpdateCheckBox(chkLoop, objects, "babylonjs_autoanimateloop");
+            Tools.UpdateNumericUpDown(nupFrom, objects, "babylonjs_autoanimate_from");
+            Tools.UpdateNumericUpDown(nupTo, objects, "babylonjs_autoanimate_to");
+
+            Tools.UpdateNumericUpDown(nupAlphaIndex, objects, "babylonjs_alphaindex");
+            Tools.UpdateNumericUpDown(nupMass, objects, "babylonjs_mass");
+            Tools.UpdateNumericUpDown(nupFriction, objects, "babylonjs_friction");
+            Tools.UpdateNumericUpDown(nupRestitution, objects, "babylonjs_restitution");
+            Tools.UpdateComboBox(cbImpostor, objects, "babylonjs_impostor");
+
+            Tools.UpdateCheckBox(chkAutoPlay, objects, "babylonjs_sound_autoplay");
+            Tools.UpdateCheckBox(chkLoop, objects, "babylonjs_sound_loop");
+            Tools.UpdateNumericUpDown(nupVolume, objects, "babylonjs_sound_volume");
+            Tools.UpdateNumericUpDown(nupPlaybackRate, objects, "babylonjs_sound_playbackrate");
+
+            Tools.UpdateComboBox(cbDistanceModel, objects, "babylonjs_sound_distancemodel");
+            Tools.UpdateNumericUpDown(nupMaxDistance, objects, "babylonjs_sound_maxdistance");
+            Tools.UpdateNumericUpDown(nupRolloff, objects, "babylonjs_sound_rolloff");
+            Tools.UpdateNumericUpDown(nupRefDistance, objects, "babylonjs_sound_refdistance");
+
+            Tools.UpdateCheckBox(chkDirectional, objects, "babylonjs_sound_directional");
+            Tools.UpdateNumericUpDown(nupConeInnerAngle, objects, "babylonjs_sound_coneinnerangle");
+            Tools.UpdateNumericUpDown(nupConeOuterAngle, objects, "babylonjs_sound_coneouterangle");
+            Tools.UpdateNumericUpDown(nupConeOuterGain, objects, "babylonjs_sound_coneoutergain");
+
+            Tools.UpdateTextBox(txtSound, objects, "babylonjs_sound_filename");
+        }
+
+        private void ObjectPropertiesForm_Load(object sender, EventArgs e)
+        {
+            for (var index = 0; index < Loader.Core.SelNodeCount; index++)
+            {
+                var node = Loader.Core.GetSelNode(index);
+
+                if (node.ObjectRef != null && 
+                    (
+                    node.ObjectRef.Eval(0).Obj.SuperClassID == SClass_ID.Geomobject
+                    ||
+                    node.ObjectRef.Eval(0).Obj.SuperClassID == SClass_ID.Helper
+                    ))
+                {
+                    objects.Add(node);
+                }
+            }
+
+            Tools.PrepareCheckBox(chkNoExport, objects, "babylonjs_noexport");
+            Tools.PrepareCheckBox(chkCollisions, objects, "babylonjs_checkcollisions");
+            Tools.PrepareCheckBox(chkPickable, objects, "babylonjs_checkpickable");
+            Tools.PrepareCheckBox(chkOptimize, objects, "babylonjs_optimizevertices");
+            Tools.PrepareCheckBox(chkShowBoundingBox, objects, "babylonjs_showboundingbox");
+            Tools.PrepareCheckBox(chkShowSubMeshesBoundingBox, objects, "babylonjs_showsubmeshesboundingbox");
+
+            Tools.PrepareCheckBox(chkAutoAnimate, objects, "babylonjs_autoanimate", 1);
+            Tools.PrepareCheckBox(chkLoop, objects, "babylonjs_autoanimateloop", 1);
+            Tools.PrepareNumericUpDown(nupFrom, objects, "babylonjs_autoanimate_from");
+            Tools.PrepareNumericUpDown(nupTo, objects, "babylonjs_autoanimate_to", 100.0f);
+            Tools.PrepareNumericUpDown(nupAlphaIndex, objects, "babylonjs_alphaindex", 1000);
+
+            Tools.PrepareNumericUpDown(nupMass, objects, "babylonjs_mass");
+            Tools.PrepareNumericUpDown(nupFriction, objects, "babylonjs_friction", 0.2f);
+            Tools.PrepareNumericUpDown(nupRestitution, objects, "babylonjs_restitution", 0.2f);
+
+            Tools.PrepareComboBox(cbImpostor, objects[0], "babylonjs_impostor", "None");
+
+            Tools.PrepareCheckBox(chkAutoPlay, objects, "babylonjs_sound_autoplay", 1);
+            Tools.PrepareCheckBox(chkLoop, objects, "babylonjs_sound_loop", 1);
+            Tools.PrepareNumericUpDown(nupVolume, objects, "babylonjs_sound_volume", 1.0f);
+            Tools.PrepareNumericUpDown(nupPlaybackRate, objects, "babylonjs_sound_playbackrate", 1.0f);
+
+            Tools.PrepareComboBox(cbDistanceModel, objects[0], "babylonjs_sound_distancemodel", "linear");
+            Tools.PrepareNumericUpDown(nupMaxDistance, objects, "babylonjs_sound_maxdistance", 100.0f);
+            Tools.PrepareNumericUpDown(nupRolloff, objects, "babylonjs_sound_rolloff", 1.0f);
+            Tools.PrepareNumericUpDown(nupRefDistance, objects, "babylonjs_sound_refdistance", 1.0f);
+
+            Tools.PrepareCheckBox(chkDirectional, objects, "babylonjs_sound_directional", 0);
+            Tools.PrepareNumericUpDown(nupConeInnerAngle, objects, "babylonjs_sound_coneinnerangle", 360.00f);
+            Tools.PrepareNumericUpDown(nupConeOuterAngle, objects, "babylonjs_sound_coneouterangle", 360.00f);
+            Tools.PrepareNumericUpDown(nupConeOuterGain, objects, "babylonjs_sound_coneoutergain", 1.0f);
+
+            Tools.PrepareTextBox(txtSound, objects[0], "babylonjs_sound_filename");
+        }
+
+        private void chkAutoAnimate_CheckedChanged(object sender, EventArgs e)
+        {
+            grpAutoAnimate.Enabled = chkAutoAnimate.Checked;
+        }
+
+        private void chkDirectional_CheckedChanged(object sender, EventArgs e)
+        {
+            grpDirectional.Enabled = chkDirectional.Checked;
+        }
+
+        private void cmdFileBrowse_Click(object sender, EventArgs e)
+        {
+            if (ofdOpenSound.ShowDialog() == DialogResult.OK)
+            {
+                txtSound.Text = ofdOpenSound.FileName;
+            }
+        }
+    }
+}

+ 122 - 122
Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.resx

@@ -1,123 +1,123 @@
-<?xml version="1.0" encoding="utf-8"?>
-<root>
-  <!-- 
-    Microsoft ResX Schema 
-    
-    Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
-    associated with the data types.
-    
-    Example:
-    
-    ... ado.net/XML headers & schema ...
-    <resheader name="resmimetype">text/microsoft-resx</resheader>
-    <resheader name="version">2.0</resheader>
-    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
-    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
-    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
-    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
-    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
-        <value>[base64 mime encoded serialized .NET Framework object]</value>
-    </data>
-    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
-        <comment>This is a comment</comment>
-    </data>
-                
-    There are any number of "resheader" rows that contain simple 
-    name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
-    mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
-    extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
-    read any of the formats listed below.
-    
-    mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
-            : and then encoded with base64 encoding.
-    
-    mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
-            : and then encoded with base64 encoding.
-
-    mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
-            : using a System.ComponentModel.TypeConverter
-            : and then encoded with base64 encoding.
-    -->
-  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
-    <xsd:element name="root" msdata:IsDataSet="true">
-      <xsd:complexType>
-        <xsd:choice maxOccurs="unbounded">
-          <xsd:element name="metadata">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" />
-              </xsd:sequence>
-              <xsd:attribute name="name" use="required" type="xsd:string" />
-              <xsd:attribute name="type" type="xsd:string" />
-              <xsd:attribute name="mimetype" type="xsd:string" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="assembly">
-            <xsd:complexType>
-              <xsd:attribute name="alias" type="xsd:string" />
-              <xsd:attribute name="name" type="xsd:string" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="data">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
-              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
-              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="resheader">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" />
-            </xsd:complexType>
-          </xsd:element>
-        </xsd:choice>
-      </xsd:complexType>
-    </xsd:element>
-  </xsd:schema>
-  <resheader name="resmimetype">
-    <value>text/microsoft-resx</value>
-  </resheader>
-  <resheader name="version">
-    <value>2.0</value>
-  </resheader>
-  <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <metadata name="ofdOpenSound.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>17, 17</value>
-  </metadata>
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="ofdOpenSound.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
 </root>

+ 286 - 272
Exporters/3ds Max/Max2Babylon/Forms/ScenePropertiesForm.Designer.cs

@@ -1,273 +1,287 @@
-namespace Max2Babylon
-{
-    partial class ScenePropertiesForm
-    {
-        /// <summary>
-        /// Required designer variable.
-        /// </summary>
-        private System.ComponentModel.IContainer components = null;
-
-        /// <summary>
-        /// Clean up any resources being used.
-        /// </summary>
-        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing && (components != null))
-            {
-                components.Dispose();
-            }
-            base.Dispose(disposing);
-        }
-
-        #region Windows Form Designer generated code
-
-        /// <summary>
-        /// Required method for Designer support - do not modify
-        /// the contents of this method with the code editor.
-        /// </summary>
-        private void InitializeComponent()
-        {
-            this.groupBox1 = new System.Windows.Forms.GroupBox();
-            this.gravityControl = new Max2Babylon.Vector3Control();
-            this.label3 = new System.Windows.Forms.Label();
-            this.butCancel = new System.Windows.Forms.Button();
-            this.butOK = new System.Windows.Forms.Button();
-            this.groupBox2 = new System.Windows.Forms.GroupBox();
-            this.chkQuaternions = new System.Windows.Forms.CheckBox();
-            this.groupBox3 = new System.Windows.Forms.GroupBox();
-            this.cmdBrowse = new System.Windows.Forms.Button();
-            this.txtSound = new System.Windows.Forms.TextBox();
-            this.chkLoop = new System.Windows.Forms.CheckBox();
-            this.chkAutoPlay = new System.Windows.Forms.CheckBox();
-            this.ofdOpenSound = new System.Windows.Forms.OpenFileDialog();
-            this.nupVolume = new System.Windows.Forms.NumericUpDown();
-            this.lblVolume = new System.Windows.Forms.Label();
-            this.groupBox1.SuspendLayout();
-            this.groupBox2.SuspendLayout();
-            this.groupBox3.SuspendLayout();
-            ((System.ComponentModel.ISupportInitialize)(this.nupVolume)).BeginInit();
-            this.SuspendLayout();
-            // 
-            // groupBox1
-            // 
-            this.groupBox1.Controls.Add(this.gravityControl);
-            this.groupBox1.Controls.Add(this.label3);
-            this.groupBox1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.groupBox1.Location = new System.Drawing.Point(12, 12);
-            this.groupBox1.Name = "groupBox1";
-            this.groupBox1.Size = new System.Drawing.Size(319, 87);
-            this.groupBox1.TabIndex = 0;
-            this.groupBox1.TabStop = false;
-            this.groupBox1.Text = "Collisions";
-            // 
-            // gravityControl
-            // 
-            this.gravityControl.Location = new System.Drawing.Point(21, 44);
-            this.gravityControl.Name = "gravityControl";
-            this.gravityControl.Size = new System.Drawing.Size(294, 28);
-            this.gravityControl.TabIndex = 5;
-            this.gravityControl.X = 0F;
-            this.gravityControl.Y = 0F;
-            this.gravityControl.Z = 0F;
-            // 
-            // label3
-            // 
-            this.label3.AutoSize = true;
-            this.label3.Location = new System.Drawing.Point(18, 28);
-            this.label3.Name = "label3";
-            this.label3.Size = new System.Drawing.Size(43, 13);
-            this.label3.TabIndex = 4;
-            this.label3.Text = "Gravity:";
-            // 
-            // butCancel
-            // 
-            this.butCancel.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
-            this.butCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
-            this.butCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butCancel.Location = new System.Drawing.Point(174, 351);
-            this.butCancel.Name = "butCancel";
-            this.butCancel.Size = new System.Drawing.Size(75, 23);
-            this.butCancel.TabIndex = 4;
-            this.butCancel.Text = "Cancel";
-            this.butCancel.UseVisualStyleBackColor = true;
-            // 
-            // butOK
-            // 
-            this.butOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
-            this.butOK.DialogResult = System.Windows.Forms.DialogResult.OK;
-            this.butOK.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butOK.Location = new System.Drawing.Point(93, 351);
-            this.butOK.Name = "butOK";
-            this.butOK.Size = new System.Drawing.Size(75, 23);
-            this.butOK.TabIndex = 3;
-            this.butOK.Text = "OK";
-            this.butOK.UseVisualStyleBackColor = true;
-            this.butOK.Click += new System.EventHandler(this.butOK_Click);
-            // 
-            // groupBox2
-            // 
-            this.groupBox2.Controls.Add(this.chkQuaternions);
-            this.groupBox2.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.groupBox2.Location = new System.Drawing.Point(12, 105);
-            this.groupBox2.Name = "groupBox2";
-            this.groupBox2.Size = new System.Drawing.Size(319, 87);
-            this.groupBox2.TabIndex = 5;
-            this.groupBox2.TabStop = false;
-            this.groupBox2.Text = "Advanced";
-            // 
-            // chkQuaternions
-            // 
-            this.chkQuaternions.AutoSize = true;
-            this.chkQuaternions.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.chkQuaternions.Location = new System.Drawing.Point(21, 28);
-            this.chkQuaternions.Name = "chkQuaternions";
-            this.chkQuaternions.Size = new System.Drawing.Size(221, 17);
-            this.chkQuaternions.TabIndex = 2;
-            this.chkQuaternions.Text = "Export quaternions instead of Euler angles";
-            this.chkQuaternions.UseVisualStyleBackColor = true;
-            // 
-            // groupBox3
-            // 
-            this.groupBox3.Controls.Add(this.nupVolume);
-            this.groupBox3.Controls.Add(this.lblVolume);
-            this.groupBox3.Controls.Add(this.cmdBrowse);
-            this.groupBox3.Controls.Add(this.txtSound);
-            this.groupBox3.Controls.Add(this.chkLoop);
-            this.groupBox3.Controls.Add(this.chkAutoPlay);
-            this.groupBox3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.groupBox3.Location = new System.Drawing.Point(12, 198);
-            this.groupBox3.Name = "groupBox3";
-            this.groupBox3.Size = new System.Drawing.Size(319, 136);
-            this.groupBox3.TabIndex = 6;
-            this.groupBox3.TabStop = false;
-            this.groupBox3.Text = "Sound";
-            // 
-            // cmdBrowse
-            // 
-            this.cmdBrowse.Anchor = System.Windows.Forms.AnchorStyles.Right;
-            this.cmdBrowse.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.cmdBrowse.Location = new System.Drawing.Point(276, 28);
-            this.cmdBrowse.Name = "cmdBrowse";
-            this.cmdBrowse.Size = new System.Drawing.Size(37, 23);
-            this.cmdBrowse.TabIndex = 6;
-            this.cmdBrowse.Text = "...";
-            this.cmdBrowse.UseVisualStyleBackColor = true;
-            this.cmdBrowse.Click += new System.EventHandler(this.cmdBrowse_Click);
-            // 
-            // txtSound
-            // 
-            this.txtSound.Location = new System.Drawing.Point(21, 28);
-            this.txtSound.Name = "txtSound";
-            this.txtSound.Size = new System.Drawing.Size(249, 20);
-            this.txtSound.TabIndex = 5;
-            // 
-            // chkLoop
-            // 
-            this.chkLoop.AutoSize = true;
-            this.chkLoop.Checked = true;
-            this.chkLoop.CheckState = System.Windows.Forms.CheckState.Checked;
-            this.chkLoop.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.chkLoop.Location = new System.Drawing.Point(21, 77);
-            this.chkLoop.Name = "chkLoop";
-            this.chkLoop.Size = new System.Drawing.Size(47, 17);
-            this.chkLoop.TabIndex = 4;
-            this.chkLoop.Text = "Loop";
-            this.chkLoop.UseVisualStyleBackColor = true;
-            // 
-            // chkAutoPlay
-            // 
-            this.chkAutoPlay.AutoSize = true;
-            this.chkAutoPlay.Checked = true;
-            this.chkAutoPlay.CheckState = System.Windows.Forms.CheckState.Checked;
-            this.chkAutoPlay.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.chkAutoPlay.Location = new System.Drawing.Point(21, 54);
-            this.chkAutoPlay.Name = "chkAutoPlay";
-            this.chkAutoPlay.Size = new System.Drawing.Size(67, 17);
-            this.chkAutoPlay.TabIndex = 3;
-            this.chkAutoPlay.Text = "Auto play";
-            this.chkAutoPlay.UseVisualStyleBackColor = true;
-            // 
-            // ofdOpenSound
-            // 
-            this.ofdOpenSound.Filter = "Sound files|*.wav;*.mp3";
-            // 
-            // nupVolume
-            // 
-            this.nupVolume.DecimalPlaces = 2;
-            this.nupVolume.Increment = new decimal(new int[] {
-            1,
-            0,
-            0,
-            65536});
-            this.nupVolume.Location = new System.Drawing.Point(150, 108);
-            this.nupVolume.Maximum = new decimal(new int[] {
-            10,
-            0,
-            0,
-            0});
-            this.nupVolume.Name = "nupVolume";
-            this.nupVolume.Size = new System.Drawing.Size(120, 20);
-            this.nupVolume.TabIndex = 10;
-            this.nupVolume.Value = new decimal(new int[] {
-            1,
-            0,
-            0,
-            0});
-            // 
-            // lblVolume
-            // 
-            this.lblVolume.AutoSize = true;
-            this.lblVolume.Location = new System.Drawing.Point(18, 110);
-            this.lblVolume.Name = "lblVolume";
-            this.lblVolume.Size = new System.Drawing.Size(45, 13);
-            this.lblVolume.TabIndex = 9;
-            this.lblVolume.Text = "Volume:";
-            // 
-            // ScenePropertiesForm
-            // 
-            this.AcceptButton = this.butOK;
-            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.CancelButton = this.butCancel;
-            this.ClientSize = new System.Drawing.Size(343, 386);
-            this.Controls.Add(this.groupBox3);
-            this.Controls.Add(this.groupBox2);
-            this.Controls.Add(this.butCancel);
-            this.Controls.Add(this.butOK);
-            this.Controls.Add(this.groupBox1);
-            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
-            this.Name = "ScenePropertiesForm";
-            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
-            this.Text = "Babylon.js - Scene Properties";
-            this.Load += new System.EventHandler(this.ScenePropertiesForm_Load);
-            this.groupBox1.ResumeLayout(false);
-            this.groupBox1.PerformLayout();
-            this.groupBox2.ResumeLayout(false);
-            this.groupBox2.PerformLayout();
-            this.groupBox3.ResumeLayout(false);
-            this.groupBox3.PerformLayout();
-            ((System.ComponentModel.ISupportInitialize)(this.nupVolume)).EndInit();
-            this.ResumeLayout(false);
-
-        }
-
-        #endregion
-
-        private System.Windows.Forms.GroupBox groupBox1;
-        private Vector3Control gravityControl;
-        private System.Windows.Forms.Label label3;
-        private System.Windows.Forms.Button butCancel;
-        private System.Windows.Forms.Button butOK;
-        private System.Windows.Forms.GroupBox groupBox2;
-        private System.Windows.Forms.CheckBox chkQuaternions;
-        private System.Windows.Forms.GroupBox groupBox3;
-        private System.Windows.Forms.CheckBox chkLoop;
-        private System.Windows.Forms.CheckBox chkAutoPlay;
-        private System.Windows.Forms.Button cmdBrowse;
-        private System.Windows.Forms.TextBox txtSound;
-        private System.Windows.Forms.OpenFileDialog ofdOpenSound;
-        private System.Windows.Forms.NumericUpDown nupVolume;
-        private System.Windows.Forms.Label lblVolume;
-    }
+namespace Max2Babylon
+{
+    partial class ScenePropertiesForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.groupBox1 = new System.Windows.Forms.GroupBox();
+            this.gravityControl = new Max2Babylon.Vector3Control();
+            this.label3 = new System.Windows.Forms.Label();
+            this.butCancel = new System.Windows.Forms.Button();
+            this.butOK = new System.Windows.Forms.Button();
+            this.groupBox2 = new System.Windows.Forms.GroupBox();
+            this.chkAnimations = new System.Windows.Forms.CheckBox();
+            this.chkQuaternions = new System.Windows.Forms.CheckBox();
+            this.groupBox3 = new System.Windows.Forms.GroupBox();
+            this.nupVolume = new System.Windows.Forms.NumericUpDown();
+            this.lblVolume = new System.Windows.Forms.Label();
+            this.cmdBrowse = new System.Windows.Forms.Button();
+            this.txtSound = new System.Windows.Forms.TextBox();
+            this.chkLoop = new System.Windows.Forms.CheckBox();
+            this.chkAutoPlay = new System.Windows.Forms.CheckBox();
+            this.ofdOpenSound = new System.Windows.Forms.OpenFileDialog();
+            this.groupBox1.SuspendLayout();
+            this.groupBox2.SuspendLayout();
+            this.groupBox3.SuspendLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupVolume)).BeginInit();
+            this.SuspendLayout();
+            // 
+            // groupBox1
+            // 
+            this.groupBox1.Controls.Add(this.gravityControl);
+            this.groupBox1.Controls.Add(this.label3);
+            this.groupBox1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.groupBox1.Location = new System.Drawing.Point(12, 12);
+            this.groupBox1.Name = "groupBox1";
+            this.groupBox1.Size = new System.Drawing.Size(319, 87);
+            this.groupBox1.TabIndex = 0;
+            this.groupBox1.TabStop = false;
+            this.groupBox1.Text = "Collisions";
+            // 
+            // gravityControl
+            // 
+            this.gravityControl.Location = new System.Drawing.Point(21, 44);
+            this.gravityControl.Name = "gravityControl";
+            this.gravityControl.Size = new System.Drawing.Size(294, 28);
+            this.gravityControl.TabIndex = 5;
+            this.gravityControl.X = 0F;
+            this.gravityControl.Y = 0F;
+            this.gravityControl.Z = 0F;
+            // 
+            // label3
+            // 
+            this.label3.AutoSize = true;
+            this.label3.Location = new System.Drawing.Point(18, 28);
+            this.label3.Name = "label3";
+            this.label3.Size = new System.Drawing.Size(43, 13);
+            this.label3.TabIndex = 4;
+            this.label3.Text = "Gravity:";
+            // 
+            // butCancel
+            // 
+            this.butCancel.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
+            this.butCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.butCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.butCancel.Location = new System.Drawing.Point(174, 351);
+            this.butCancel.Name = "butCancel";
+            this.butCancel.Size = new System.Drawing.Size(75, 23);
+            this.butCancel.TabIndex = 4;
+            this.butCancel.Text = "Cancel";
+            this.butCancel.UseVisualStyleBackColor = true;
+            // 
+            // butOK
+            // 
+            this.butOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
+            this.butOK.DialogResult = System.Windows.Forms.DialogResult.OK;
+            this.butOK.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.butOK.Location = new System.Drawing.Point(93, 351);
+            this.butOK.Name = "butOK";
+            this.butOK.Size = new System.Drawing.Size(75, 23);
+            this.butOK.TabIndex = 3;
+            this.butOK.Text = "OK";
+            this.butOK.UseVisualStyleBackColor = true;
+            this.butOK.Click += new System.EventHandler(this.butOK_Click);
+            // 
+            // groupBox2
+            // 
+            this.groupBox2.Controls.Add(this.chkAnimations);
+            this.groupBox2.Controls.Add(this.chkQuaternions);
+            this.groupBox2.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.groupBox2.Location = new System.Drawing.Point(12, 105);
+            this.groupBox2.Name = "groupBox2";
+            this.groupBox2.Size = new System.Drawing.Size(319, 87);
+            this.groupBox2.TabIndex = 5;
+            this.groupBox2.TabStop = false;
+            this.groupBox2.Text = "Advanced";
+            // 
+            // chkAnimations
+            // 
+            this.chkAnimations.AutoSize = true;
+            this.chkAnimations.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkAnimations.Location = new System.Drawing.Point(21, 51);
+            this.chkAnimations.Name = "chkAnimations";
+            this.chkAnimations.Size = new System.Drawing.Size(149, 17);
+            this.chkAnimations.TabIndex = 3;
+            this.chkAnimations.Text = "Do not optimize animations";
+            this.chkAnimations.UseVisualStyleBackColor = true;
+            // 
+            // chkQuaternions
+            // 
+            this.chkQuaternions.AutoSize = true;
+            this.chkQuaternions.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkQuaternions.Location = new System.Drawing.Point(21, 28);
+            this.chkQuaternions.Name = "chkQuaternions";
+            this.chkQuaternions.Size = new System.Drawing.Size(221, 17);
+            this.chkQuaternions.TabIndex = 2;
+            this.chkQuaternions.Text = "Export quaternions instead of Euler angles";
+            this.chkQuaternions.UseVisualStyleBackColor = true;
+            // 
+            // groupBox3
+            // 
+            this.groupBox3.Controls.Add(this.nupVolume);
+            this.groupBox3.Controls.Add(this.lblVolume);
+            this.groupBox3.Controls.Add(this.cmdBrowse);
+            this.groupBox3.Controls.Add(this.txtSound);
+            this.groupBox3.Controls.Add(this.chkLoop);
+            this.groupBox3.Controls.Add(this.chkAutoPlay);
+            this.groupBox3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.groupBox3.Location = new System.Drawing.Point(12, 198);
+            this.groupBox3.Name = "groupBox3";
+            this.groupBox3.Size = new System.Drawing.Size(319, 136);
+            this.groupBox3.TabIndex = 6;
+            this.groupBox3.TabStop = false;
+            this.groupBox3.Text = "Sound";
+            // 
+            // nupVolume
+            // 
+            this.nupVolume.DecimalPlaces = 2;
+            this.nupVolume.Increment = new decimal(new int[] {
+            1,
+            0,
+            0,
+            65536});
+            this.nupVolume.Location = new System.Drawing.Point(150, 108);
+            this.nupVolume.Maximum = new decimal(new int[] {
+            10,
+            0,
+            0,
+            0});
+            this.nupVolume.Name = "nupVolume";
+            this.nupVolume.Size = new System.Drawing.Size(120, 20);
+            this.nupVolume.TabIndex = 10;
+            this.nupVolume.Value = new decimal(new int[] {
+            1,
+            0,
+            0,
+            0});
+            // 
+            // lblVolume
+            // 
+            this.lblVolume.AutoSize = true;
+            this.lblVolume.Location = new System.Drawing.Point(18, 110);
+            this.lblVolume.Name = "lblVolume";
+            this.lblVolume.Size = new System.Drawing.Size(45, 13);
+            this.lblVolume.TabIndex = 9;
+            this.lblVolume.Text = "Volume:";
+            // 
+            // cmdBrowse
+            // 
+            this.cmdBrowse.Anchor = System.Windows.Forms.AnchorStyles.Right;
+            this.cmdBrowse.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.cmdBrowse.Location = new System.Drawing.Point(276, 28);
+            this.cmdBrowse.Name = "cmdBrowse";
+            this.cmdBrowse.Size = new System.Drawing.Size(37, 23);
+            this.cmdBrowse.TabIndex = 6;
+            this.cmdBrowse.Text = "...";
+            this.cmdBrowse.UseVisualStyleBackColor = true;
+            this.cmdBrowse.Click += new System.EventHandler(this.cmdBrowse_Click);
+            // 
+            // txtSound
+            // 
+            this.txtSound.Location = new System.Drawing.Point(21, 28);
+            this.txtSound.Name = "txtSound";
+            this.txtSound.Size = new System.Drawing.Size(249, 20);
+            this.txtSound.TabIndex = 5;
+            // 
+            // chkLoop
+            // 
+            this.chkLoop.AutoSize = true;
+            this.chkLoop.Checked = true;
+            this.chkLoop.CheckState = System.Windows.Forms.CheckState.Checked;
+            this.chkLoop.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkLoop.Location = new System.Drawing.Point(21, 77);
+            this.chkLoop.Name = "chkLoop";
+            this.chkLoop.Size = new System.Drawing.Size(47, 17);
+            this.chkLoop.TabIndex = 4;
+            this.chkLoop.Text = "Loop";
+            this.chkLoop.UseVisualStyleBackColor = true;
+            // 
+            // chkAutoPlay
+            // 
+            this.chkAutoPlay.AutoSize = true;
+            this.chkAutoPlay.Checked = true;
+            this.chkAutoPlay.CheckState = System.Windows.Forms.CheckState.Checked;
+            this.chkAutoPlay.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkAutoPlay.Location = new System.Drawing.Point(21, 54);
+            this.chkAutoPlay.Name = "chkAutoPlay";
+            this.chkAutoPlay.Size = new System.Drawing.Size(67, 17);
+            this.chkAutoPlay.TabIndex = 3;
+            this.chkAutoPlay.Text = "Auto play";
+            this.chkAutoPlay.UseVisualStyleBackColor = true;
+            // 
+            // ofdOpenSound
+            // 
+            this.ofdOpenSound.Filter = "Sound files|*.wav;*.mp3";
+            // 
+            // ScenePropertiesForm
+            // 
+            this.AcceptButton = this.butOK;
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.CancelButton = this.butCancel;
+            this.ClientSize = new System.Drawing.Size(343, 386);
+            this.Controls.Add(this.groupBox3);
+            this.Controls.Add(this.groupBox2);
+            this.Controls.Add(this.butCancel);
+            this.Controls.Add(this.butOK);
+            this.Controls.Add(this.groupBox1);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
+            this.Name = "ScenePropertiesForm";
+            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+            this.Text = "Babylon.js - Scene Properties";
+            this.Load += new System.EventHandler(this.ScenePropertiesForm_Load);
+            this.groupBox1.ResumeLayout(false);
+            this.groupBox1.PerformLayout();
+            this.groupBox2.ResumeLayout(false);
+            this.groupBox2.PerformLayout();
+            this.groupBox3.ResumeLayout(false);
+            this.groupBox3.PerformLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupVolume)).EndInit();
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.GroupBox groupBox1;
+        private Vector3Control gravityControl;
+        private System.Windows.Forms.Label label3;
+        private System.Windows.Forms.Button butCancel;
+        private System.Windows.Forms.Button butOK;
+        private System.Windows.Forms.GroupBox groupBox2;
+        private System.Windows.Forms.CheckBox chkQuaternions;
+        private System.Windows.Forms.GroupBox groupBox3;
+        private System.Windows.Forms.CheckBox chkLoop;
+        private System.Windows.Forms.CheckBox chkAutoPlay;
+        private System.Windows.Forms.Button cmdBrowse;
+        private System.Windows.Forms.TextBox txtSound;
+        private System.Windows.Forms.OpenFileDialog ofdOpenSound;
+        private System.Windows.Forms.NumericUpDown nupVolume;
+        private System.Windows.Forms.Label lblVolume;
+        private System.Windows.Forms.CheckBox chkAnimations;
+    }
 }

+ 49 - 47
Exporters/3ds Max/Max2Babylon/Forms/ScenePropertiesForm.cs

@@ -1,47 +1,49 @@
-using System;
-using System.Collections.Generic;
-using System.Windows.Forms;
-using Autodesk.Max;
-
-namespace Max2Babylon
-{
-    public partial class ScenePropertiesForm : Form
-    {
-        public ScenePropertiesForm()
-        {
-            InitializeComponent();
-        }
-
-        private void butOK_Click(object sender, EventArgs e)
-        {
-            Tools.UpdateVector3Control(gravityControl, Loader.Core.RootNode, "babylonjs_gravity");
-            Tools.UpdateCheckBox(chkQuaternions, Loader.Core.RootNode, "babylonjs_exportquaternions");
-
-            Tools.UpdateCheckBox(chkAutoPlay, Loader.Core.RootNode, "babylonjs_sound_autoplay");
-            Tools.UpdateCheckBox(chkLoop, Loader.Core.RootNode, "babylonjs_sound_loop");
-            Tools.UpdateNumericUpDown(nupVolume, new List<IINode> { Loader.Core.RootNode }, "babylonjs_sound_volume");
-
-            Tools.UpdateTextBox(txtSound, new List<IINode> { Loader.Core.RootNode }, "babylonjs_sound_filename");
-        }
-
-        private void ScenePropertiesForm_Load(object sender, EventArgs e)
-        {
-            Tools.PrepareVector3Control(gravityControl, Loader.Core.RootNode, "babylonjs_gravity", 0, -0.9f);
-            Tools.PrepareCheckBox(chkQuaternions, Loader.Core.RootNode, "babylonjs_exportquaternions", 1);
-
-            Tools.PrepareCheckBox(chkAutoPlay, Loader.Core.RootNode, "babylonjs_sound_autoplay", 1);
-            Tools.PrepareCheckBox(chkLoop, Loader.Core.RootNode, "babylonjs_sound_loop", 1);
-            Tools.PrepareNumericUpDown(nupVolume, new List<IINode>{Loader.Core.RootNode}, "babylonjs_sound_volume", 1.0f);
-
-            Tools.PrepareTextBox(txtSound, Loader.Core.RootNode, "babylonjs_sound_filename");
-        }
-
-        private void cmdBrowse_Click(object sender, EventArgs e)
-        {
-            if (ofdOpenSound.ShowDialog() == DialogResult.OK)
-            {
-                txtSound.Text = ofdOpenSound.FileName;
-            }
-        }
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+using Autodesk.Max;
+
+namespace Max2Babylon
+{
+    public partial class ScenePropertiesForm : Form
+    {
+        public ScenePropertiesForm()
+        {
+            InitializeComponent();
+        }
+
+        private void butOK_Click(object sender, EventArgs e)
+        {
+            Tools.UpdateVector3Control(gravityControl, Loader.Core.RootNode, "babylonjs_gravity");
+            Tools.UpdateCheckBox(chkQuaternions, Loader.Core.RootNode, "babylonjs_exportquaternions");
+            Tools.UpdateCheckBox(chkAnimations, Loader.Core.RootNode, "babylonjs_exportnonoptimizedanimations");
+
+            Tools.UpdateCheckBox(chkAutoPlay, Loader.Core.RootNode, "babylonjs_sound_autoplay");
+            Tools.UpdateCheckBox(chkLoop, Loader.Core.RootNode, "babylonjs_sound_loop");
+            Tools.UpdateNumericUpDown(nupVolume, new List<IINode> { Loader.Core.RootNode }, "babylonjs_sound_volume");
+
+            Tools.UpdateTextBox(txtSound, new List<IINode> { Loader.Core.RootNode }, "babylonjs_sound_filename");
+        }
+
+        private void ScenePropertiesForm_Load(object sender, EventArgs e)
+        {
+            Tools.PrepareVector3Control(gravityControl, Loader.Core.RootNode, "babylonjs_gravity", 0, -0.9f);
+            Tools.PrepareCheckBox(chkQuaternions, Loader.Core.RootNode, "babylonjs_exportquaternions", 1);
+            Tools.PrepareCheckBox(chkAnimations, Loader.Core.RootNode, "babylonjs_exportnonoptimizedanimations", 0);
+
+            Tools.PrepareCheckBox(chkAutoPlay, Loader.Core.RootNode, "babylonjs_sound_autoplay", 1);
+            Tools.PrepareCheckBox(chkLoop, Loader.Core.RootNode, "babylonjs_sound_loop", 1);
+            Tools.PrepareNumericUpDown(nupVolume, new List<IINode>{Loader.Core.RootNode}, "babylonjs_sound_volume", 1.0f);
+
+            Tools.PrepareTextBox(txtSound, Loader.Core.RootNode, "babylonjs_sound_filename");
+        }
+
+        private void cmdBrowse_Click(object sender, EventArgs e)
+        {
+            if (ofdOpenSound.ShowDialog() == DialogResult.OK)
+            {
+                txtSound.Text = ofdOpenSound.FileName;
+            }
+        }
+    }
+}

+ 122 - 122
Exporters/3ds Max/Max2Babylon/Forms/ScenePropertiesForm.resx

@@ -1,123 +1,123 @@
-<?xml version="1.0" encoding="utf-8"?>
-<root>
-  <!-- 
-    Microsoft ResX Schema 
-    
-    Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
-    associated with the data types.
-    
-    Example:
-    
-    ... ado.net/XML headers & schema ...
-    <resheader name="resmimetype">text/microsoft-resx</resheader>
-    <resheader name="version">2.0</resheader>
-    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
-    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
-    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
-    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
-    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
-        <value>[base64 mime encoded serialized .NET Framework object]</value>
-    </data>
-    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
-        <comment>This is a comment</comment>
-    </data>
-                
-    There are any number of "resheader" rows that contain simple 
-    name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
-    mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
-    extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
-    read any of the formats listed below.
-    
-    mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
-            : and then encoded with base64 encoding.
-    
-    mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
-            : and then encoded with base64 encoding.
-
-    mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
-            : using a System.ComponentModel.TypeConverter
-            : and then encoded with base64 encoding.
-    -->
-  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
-    <xsd:element name="root" msdata:IsDataSet="true">
-      <xsd:complexType>
-        <xsd:choice maxOccurs="unbounded">
-          <xsd:element name="metadata">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" />
-              </xsd:sequence>
-              <xsd:attribute name="name" use="required" type="xsd:string" />
-              <xsd:attribute name="type" type="xsd:string" />
-              <xsd:attribute name="mimetype" type="xsd:string" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="assembly">
-            <xsd:complexType>
-              <xsd:attribute name="alias" type="xsd:string" />
-              <xsd:attribute name="name" type="xsd:string" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="data">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
-              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
-              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="resheader">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" />
-            </xsd:complexType>
-          </xsd:element>
-        </xsd:choice>
-      </xsd:complexType>
-    </xsd:element>
-  </xsd:schema>
-  <resheader name="resmimetype">
-    <value>text/microsoft-resx</value>
-  </resheader>
-  <resheader name="version">
-    <value>2.0</value>
-  </resheader>
-  <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <metadata name="ofdOpenSound.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>17, 17</value>
-  </metadata>
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="ofdOpenSound.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
 </root>

+ 152 - 152
Exporters/3ds Max/Max2Babylon/Forms/Vector3Control.Designer.cs

@@ -1,152 +1,152 @@
-namespace Max2Babylon
-{
-    partial class Vector3Control
-    {
-        /// <summary> 
-        /// Required designer variable.
-        /// </summary>
-        private System.ComponentModel.IContainer components = null;
-
-        /// <summary> 
-        /// Clean up any resources being used.
-        /// </summary>
-        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing && (components != null))
-            {
-                components.Dispose();
-            }
-            base.Dispose(disposing);
-        }
-
-        #region Component Designer generated code
-
-        /// <summary> 
-        /// Required method for Designer support - do not modify 
-        /// the contents of this method with the code editor.
-        /// </summary>
-        private void InitializeComponent()
-        {
-            this.label1 = new System.Windows.Forms.Label();
-            this.nupX = new System.Windows.Forms.NumericUpDown();
-            this.nupY = new System.Windows.Forms.NumericUpDown();
-            this.label2 = new System.Windows.Forms.Label();
-            this.nupZ = new System.Windows.Forms.NumericUpDown();
-            this.label3 = new System.Windows.Forms.Label();
-            ((System.ComponentModel.ISupportInitialize)(this.nupX)).BeginInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupY)).BeginInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupZ)).BeginInit();
-            this.SuspendLayout();
-            // 
-            // label1
-            // 
-            this.label1.AutoSize = true;
-            this.label1.Location = new System.Drawing.Point(4, 6);
-            this.label1.Name = "label1";
-            this.label1.Size = new System.Drawing.Size(20, 13);
-            this.label1.TabIndex = 0;
-            this.label1.Text = "X: ";
-            // 
-            // nupX
-            // 
-            this.nupX.DecimalPlaces = 2;
-            this.nupX.Location = new System.Drawing.Point(30, 4);
-            this.nupX.Maximum = new decimal(new int[] {
-            1000000,
-            0,
-            0,
-            0});
-            this.nupX.Minimum = new decimal(new int[] {
-            1000000,
-            0,
-            0,
-            -2147483648});
-            this.nupX.Name = "nupX";
-            this.nupX.Size = new System.Drawing.Size(57, 20);
-            this.nupX.TabIndex = 1;
-            // 
-            // nupY
-            // 
-            this.nupY.DecimalPlaces = 2;
-            this.nupY.Location = new System.Drawing.Point(123, 4);
-            this.nupY.Maximum = new decimal(new int[] {
-            1000000,
-            0,
-            0,
-            0});
-            this.nupY.Minimum = new decimal(new int[] {
-            1000000,
-            0,
-            0,
-            -2147483648});
-            this.nupY.Name = "nupY";
-            this.nupY.Size = new System.Drawing.Size(57, 20);
-            this.nupY.TabIndex = 3;
-            // 
-            // label2
-            // 
-            this.label2.AutoSize = true;
-            this.label2.Location = new System.Drawing.Point(97, 6);
-            this.label2.Name = "label2";
-            this.label2.Size = new System.Drawing.Size(17, 13);
-            this.label2.TabIndex = 2;
-            this.label2.Text = "Y:";
-            // 
-            // nupZ
-            // 
-            this.nupZ.DecimalPlaces = 2;
-            this.nupZ.Location = new System.Drawing.Point(216, 4);
-            this.nupZ.Maximum = new decimal(new int[] {
-            1000000,
-            0,
-            0,
-            0});
-            this.nupZ.Minimum = new decimal(new int[] {
-            1000000,
-            0,
-            0,
-            -2147483648});
-            this.nupZ.Name = "nupZ";
-            this.nupZ.Size = new System.Drawing.Size(57, 20);
-            this.nupZ.TabIndex = 5;
-            // 
-            // label3
-            // 
-            this.label3.AutoSize = true;
-            this.label3.Location = new System.Drawing.Point(190, 6);
-            this.label3.Name = "label3";
-            this.label3.Size = new System.Drawing.Size(17, 13);
-            this.label3.TabIndex = 4;
-            this.label3.Text = "Z:";
-            // 
-            // Vector3Control
-            // 
-            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.Controls.Add(this.nupZ);
-            this.Controls.Add(this.label3);
-            this.Controls.Add(this.nupY);
-            this.Controls.Add(this.label2);
-            this.Controls.Add(this.nupX);
-            this.Controls.Add(this.label1);
-            this.Name = "Vector3Control";
-            this.Size = new System.Drawing.Size(294, 28);
-            ((System.ComponentModel.ISupportInitialize)(this.nupX)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupY)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.nupZ)).EndInit();
-            this.ResumeLayout(false);
-            this.PerformLayout();
-
-        }
-
-        #endregion
-
-        private System.Windows.Forms.Label label1;
-        private System.Windows.Forms.NumericUpDown nupX;
-        private System.Windows.Forms.NumericUpDown nupY;
-        private System.Windows.Forms.Label label2;
-        private System.Windows.Forms.NumericUpDown nupZ;
-        private System.Windows.Forms.Label label3;
-    }
-}
+namespace Max2Babylon
+{
+    partial class Vector3Control
+    {
+        /// <summary> 
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary> 
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Component Designer generated code
+
+        /// <summary> 
+        /// Required method for Designer support - do not modify 
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.label1 = new System.Windows.Forms.Label();
+            this.nupX = new System.Windows.Forms.NumericUpDown();
+            this.nupY = new System.Windows.Forms.NumericUpDown();
+            this.label2 = new System.Windows.Forms.Label();
+            this.nupZ = new System.Windows.Forms.NumericUpDown();
+            this.label3 = new System.Windows.Forms.Label();
+            ((System.ComponentModel.ISupportInitialize)(this.nupX)).BeginInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupY)).BeginInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupZ)).BeginInit();
+            this.SuspendLayout();
+            // 
+            // label1
+            // 
+            this.label1.AutoSize = true;
+            this.label1.Location = new System.Drawing.Point(4, 6);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(20, 13);
+            this.label1.TabIndex = 0;
+            this.label1.Text = "X: ";
+            // 
+            // nupX
+            // 
+            this.nupX.DecimalPlaces = 2;
+            this.nupX.Location = new System.Drawing.Point(30, 4);
+            this.nupX.Maximum = new decimal(new int[] {
+            1000000,
+            0,
+            0,
+            0});
+            this.nupX.Minimum = new decimal(new int[] {
+            1000000,
+            0,
+            0,
+            -2147483648});
+            this.nupX.Name = "nupX";
+            this.nupX.Size = new System.Drawing.Size(57, 20);
+            this.nupX.TabIndex = 1;
+            // 
+            // nupY
+            // 
+            this.nupY.DecimalPlaces = 2;
+            this.nupY.Location = new System.Drawing.Point(123, 4);
+            this.nupY.Maximum = new decimal(new int[] {
+            1000000,
+            0,
+            0,
+            0});
+            this.nupY.Minimum = new decimal(new int[] {
+            1000000,
+            0,
+            0,
+            -2147483648});
+            this.nupY.Name = "nupY";
+            this.nupY.Size = new System.Drawing.Size(57, 20);
+            this.nupY.TabIndex = 3;
+            // 
+            // label2
+            // 
+            this.label2.AutoSize = true;
+            this.label2.Location = new System.Drawing.Point(97, 6);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(17, 13);
+            this.label2.TabIndex = 2;
+            this.label2.Text = "Y:";
+            // 
+            // nupZ
+            // 
+            this.nupZ.DecimalPlaces = 2;
+            this.nupZ.Location = new System.Drawing.Point(216, 4);
+            this.nupZ.Maximum = new decimal(new int[] {
+            1000000,
+            0,
+            0,
+            0});
+            this.nupZ.Minimum = new decimal(new int[] {
+            1000000,
+            0,
+            0,
+            -2147483648});
+            this.nupZ.Name = "nupZ";
+            this.nupZ.Size = new System.Drawing.Size(57, 20);
+            this.nupZ.TabIndex = 5;
+            // 
+            // label3
+            // 
+            this.label3.AutoSize = true;
+            this.label3.Location = new System.Drawing.Point(190, 6);
+            this.label3.Name = "label3";
+            this.label3.Size = new System.Drawing.Size(17, 13);
+            this.label3.TabIndex = 4;
+            this.label3.Text = "Z:";
+            // 
+            // Vector3Control
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.Controls.Add(this.nupZ);
+            this.Controls.Add(this.label3);
+            this.Controls.Add(this.nupY);
+            this.Controls.Add(this.label2);
+            this.Controls.Add(this.nupX);
+            this.Controls.Add(this.label1);
+            this.Name = "Vector3Control";
+            this.Size = new System.Drawing.Size(294, 28);
+            ((System.ComponentModel.ISupportInitialize)(this.nupX)).EndInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupY)).EndInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupZ)).EndInit();
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.NumericUpDown nupX;
+        private System.Windows.Forms.NumericUpDown nupY;
+        private System.Windows.Forms.Label label2;
+        private System.Windows.Forms.NumericUpDown nupZ;
+        private System.Windows.Forms.Label label3;
+    }
+}

+ 30 - 30
Exporters/3ds Max/Max2Babylon/Forms/Vector3Control.cs

@@ -1,30 +1,30 @@
-using System.Windows.Forms;
-
-namespace Max2Babylon
-{
-    public partial class Vector3Control : UserControl
-    {
-        public Vector3Control()
-        {
-            InitializeComponent();
-        }
-
-        public float X
-        {
-            get { return (float)nupX.Value; }
-            set { nupX.Value = (decimal)value; }
-        }
-
-        public float Y
-        {
-            get { return (float)nupY.Value; }
-            set { nupY.Value = (decimal)value; }
-        }
-
-        public float Z
-        {
-            get { return (float)nupZ.Value; }
-            set { nupZ.Value = (decimal)value; }
-        }
-    }
-}
+using System.Windows.Forms;
+
+namespace Max2Babylon
+{
+    public partial class Vector3Control : UserControl
+    {
+        public Vector3Control()
+        {
+            InitializeComponent();
+        }
+
+        public float X
+        {
+            get { return (float)nupX.Value; }
+            set { nupX.Value = (decimal)value; }
+        }
+
+        public float Y
+        {
+            get { return (float)nupY.Value; }
+            set { nupY.Value = (decimal)value; }
+        }
+
+        public float Z
+        {
+            get { return (float)nupZ.Value; }
+            set { nupZ.Value = (decimal)value; }
+        }
+    }
+}

+ 119 - 119
Exporters/3ds Max/Max2Babylon/Forms/Vector3Control.resx

@@ -1,120 +1,120 @@
-<?xml version="1.0" encoding="utf-8"?>
-<root>
-  <!-- 
-    Microsoft ResX Schema 
-    
-    Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
-    associated with the data types.
-    
-    Example:
-    
-    ... ado.net/XML headers & schema ...
-    <resheader name="resmimetype">text/microsoft-resx</resheader>
-    <resheader name="version">2.0</resheader>
-    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
-    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
-    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
-    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
-    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
-        <value>[base64 mime encoded serialized .NET Framework object]</value>
-    </data>
-    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
-        <comment>This is a comment</comment>
-    </data>
-                
-    There are any number of "resheader" rows that contain simple 
-    name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
-    mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
-    extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
-    read any of the formats listed below.
-    
-    mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
-            : and then encoded with base64 encoding.
-    
-    mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
-            : and then encoded with base64 encoding.
-
-    mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
-            : using a System.ComponentModel.TypeConverter
-            : and then encoded with base64 encoding.
-    -->
-  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
-    <xsd:element name="root" msdata:IsDataSet="true">
-      <xsd:complexType>
-        <xsd:choice maxOccurs="unbounded">
-          <xsd:element name="metadata">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" />
-              </xsd:sequence>
-              <xsd:attribute name="name" use="required" type="xsd:string" />
-              <xsd:attribute name="type" type="xsd:string" />
-              <xsd:attribute name="mimetype" type="xsd:string" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="assembly">
-            <xsd:complexType>
-              <xsd:attribute name="alias" type="xsd:string" />
-              <xsd:attribute name="name" type="xsd:string" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="data">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
-              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
-              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="resheader">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" />
-            </xsd:complexType>
-          </xsd:element>
-        </xsd:choice>
-      </xsd:complexType>
-    </xsd:element>
-  </xsd:schema>
-  <resheader name="resmimetype">
-    <value>text/microsoft-resx</value>
-  </resheader>
-  <resheader name="version">
-    <value>2.0</value>
-  </resheader>
-  <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
 </root>

+ 128 - 128
Exporters/3ds Max/Max2Babylon/GlobalUtility.cs

@@ -1,128 +1,128 @@
-using Autodesk.Max;
-using Autodesk.Max.IQuadMenuContext;
-using Autodesk.Max.Plugins;
-
-namespace Max2Babylon
-{
-    class GlobalUtility : GUP
-    {
-        IIMenu menu;
-        IIMenuItem menuItem;
-        IIMenuItem menuItemBabylon;
-        uint idActionTable;
-        IActionTable actionTable;
-        IActionCallback actionCallback;
-
-        public override void Stop()
-        {
-            try
-            {
-                if (actionTable != null)
-                {
-                    Loader.Global.COREInterface.ActionManager.DeactivateActionTable(actionCallback, idActionTable);
-                }
-
-                // Clean up menu
-                if (menu != null)
-                {
-                    Loader.Global.COREInterface.MenuManager.UnRegisterMenu(menu);
-                    Loader.Global.ReleaseIMenu(menu);
-                    Loader.Global.ReleaseIMenuItem(menuItemBabylon);
-                    Loader.Global.ReleaseIMenuItem(menuItem);
-
-                    menu = null;
-                    menuItem = null;
-                }
-            }
-            catch
-            {
-                // Fails silently
-            }
-        }
-
-        public override uint Start
-        {
-            get
-            {
-                IIActionManager actionManager = Loader.Core.ActionManager;
-                IIMenuManager menuManager = Loader.Core.MenuManager;
-
-                // Set up global actions
-                idActionTable = (uint)actionManager.NumActionTables;
-
-                string actionTableName = "Babylon Actions";
-                actionTable = Loader.Global.ActionTable.Create(idActionTable, 0, ref actionTableName);
-                actionTable.AppendOperation(new BabylonExportActionItem());
-                actionTable.AppendOperation(new BabylonPropertiesActionItem());
-                actionTable.AppendOperation(new BabylonActionsBuilderActionItem());
-                actionCallback = new BabylonActionCallback();
-
-                actionManager.RegisterActionTable(actionTable);
-                actionManager.ActivateActionTable(actionCallback as ActionCallback, idActionTable);
-
-                // Set up menu
-                menu = menuManager.FindMenu("Babylon");
-
-                if (menu != null)
-                {
-                    menuManager.UnRegisterMenu(menu);
-                    Loader.Global.ReleaseIMenu(menu);
-                    menu = null;
-                }
-
-                // Main menu
-                menu = Loader.Global.IMenu;
-                menu.Title = "Babylon";
-                menuManager.RegisterMenu(menu, 0);
-
-                // Launch option
-                menuItemBabylon = Loader.Global.IMenuItem;
-                menuItemBabylon.Title = "&File Exporter";
-                menuItemBabylon.ActionItem = actionTable[0];
-
-                menu.AddItem(menuItemBabylon, -1);
-
-                menuItem = Loader.Global.IMenuItem;
-                menuItem.SubMenu = menu;
-
-                menuManager.MainMenuBar.AddItem(menuItem, -1);
-
-                // Quad
-                var rootQuadMenu = menuManager.GetViewportRightClickMenu(RightClickContext.NonePressed);
-                var quadMenu = rootQuadMenu.GetMenu(0);
-
-                menu = menuManager.FindMenu("Babylon...");
-
-                if (menu != null)
-                {
-                    menuManager.UnRegisterMenu(menu);
-                    Loader.Global.ReleaseIMenu(menu);
-                    menu = null;
-                }
-
-                menu = Loader.Global.IMenu;
-                menu.Title = "Babylon...";
-                menuManager.RegisterMenu(menu, 0);
-
-                menuItemBabylon = Loader.Global.IMenuItem;
-                menuItemBabylon.Title = "Babylon Properties";
-                menuItemBabylon.ActionItem = actionTable[1];
-                menu.AddItem(menuItemBabylon, -1);
-
-                menuItemBabylon = Loader.Global.IMenuItem;
-                menuItemBabylon.Title = "Babylon Actions Builder";
-                menuItemBabylon.ActionItem = actionTable[2];
-                menu.AddItem(menuItemBabylon, -1);
-
-                menuItem = Loader.Global.IMenuItem;
-                menuItem.SubMenu = menu;
-
-                quadMenu.AddItem(menuItem, -1);
-
-                Loader.Global.COREInterface.MenuManager.UpdateMenuBar();
-
-                return 0;
-            }
-        }
-    }
-}
+using Autodesk.Max;
+using Autodesk.Max.IQuadMenuContext;
+using Autodesk.Max.Plugins;
+
+namespace Max2Babylon
+{
+    class GlobalUtility : GUP
+    {
+        IIMenu menu;
+        IIMenuItem menuItem;
+        IIMenuItem menuItemBabylon;
+        uint idActionTable;
+        IActionTable actionTable;
+        IActionCallback actionCallback;
+
+        public override void Stop()
+        {
+            try
+            {
+                if (actionTable != null)
+                {
+                    Loader.Global.COREInterface.ActionManager.DeactivateActionTable(actionCallback, idActionTable);
+                }
+
+                // Clean up menu
+                if (menu != null)
+                {
+                    Loader.Global.COREInterface.MenuManager.UnRegisterMenu(menu);
+                    Loader.Global.ReleaseIMenu(menu);
+                    Loader.Global.ReleaseIMenuItem(menuItemBabylon);
+                    Loader.Global.ReleaseIMenuItem(menuItem);
+
+                    menu = null;
+                    menuItem = null;
+                }
+            }
+            catch
+            {
+                // Fails silently
+            }
+        }
+
+        public override uint Start
+        {
+            get
+            {
+                IIActionManager actionManager = Loader.Core.ActionManager;
+                IIMenuManager menuManager = Loader.Core.MenuManager;
+
+                // Set up global actions
+                idActionTable = (uint)actionManager.NumActionTables;
+
+                string actionTableName = "Babylon Actions";
+                actionTable = Loader.Global.ActionTable.Create(idActionTable, 0, ref actionTableName);
+                actionTable.AppendOperation(new BabylonExportActionItem());
+                actionTable.AppendOperation(new BabylonPropertiesActionItem());
+                actionTable.AppendOperation(new BabylonActionsBuilderActionItem());
+                actionCallback = new BabylonActionCallback();
+
+                actionManager.RegisterActionTable(actionTable);
+                actionManager.ActivateActionTable(actionCallback as ActionCallback, idActionTable);
+
+                // Set up menu
+                menu = menuManager.FindMenu("Babylon");
+
+                if (menu != null)
+                {
+                    menuManager.UnRegisterMenu(menu);
+                    Loader.Global.ReleaseIMenu(menu);
+                    menu = null;
+                }
+
+                // Main menu
+                menu = Loader.Global.IMenu;
+                menu.Title = "Babylon";
+                menuManager.RegisterMenu(menu, 0);
+
+                // Launch option
+                menuItemBabylon = Loader.Global.IMenuItem;
+                menuItemBabylon.Title = "&File Exporter";
+                menuItemBabylon.ActionItem = actionTable[0];
+
+                menu.AddItem(menuItemBabylon, -1);
+
+                menuItem = Loader.Global.IMenuItem;
+                menuItem.SubMenu = menu;
+
+                menuManager.MainMenuBar.AddItem(menuItem, -1);
+
+                // Quad
+                var rootQuadMenu = menuManager.GetViewportRightClickMenu(RightClickContext.NonePressed);
+                var quadMenu = rootQuadMenu.GetMenu(0);
+
+                menu = menuManager.FindMenu("Babylon...");
+
+                if (menu != null)
+                {
+                    menuManager.UnRegisterMenu(menu);
+                    Loader.Global.ReleaseIMenu(menu);
+                    menu = null;
+                }
+
+                menu = Loader.Global.IMenu;
+                menu.Title = "Babylon...";
+                menuManager.RegisterMenu(menu, 0);
+
+                menuItemBabylon = Loader.Global.IMenuItem;
+                menuItemBabylon.Title = "Babylon Properties";
+                menuItemBabylon.ActionItem = actionTable[1];
+                menu.AddItem(menuItemBabylon, -1);
+
+                menuItemBabylon = Loader.Global.IMenuItem;
+                menuItemBabylon.Title = "Babylon Actions Builder";
+                menuItemBabylon.ActionItem = actionTable[2];
+                menu.AddItem(menuItemBabylon, -1);
+
+                menuItem = Loader.Global.IMenuItem;
+                menuItem.SubMenu = menu;
+
+                quadMenu.AddItem(menuItem, -1);
+
+                Loader.Global.COREInterface.MenuManager.UpdateMenuBar();
+
+                return 0;
+            }
+        }
+    }
+}

+ 19 - 19
Exporters/3ds Max/Max2Babylon/JsonTextWriterOptimized.cs

@@ -1,19 +1,19 @@
-using System;
-using System.IO;
-using Newtonsoft.Json;
-
-namespace Max2Babylon
-{
-    class JsonTextWriterOptimized : JsonTextWriter
-    {
-        public JsonTextWriterOptimized(TextWriter textWriter)
-            : base(textWriter)
-        {
-        }
-        public override void WriteValue(float value)
-        {
-            value = (float)Math.Round(value, 4);
-            base.WriteValue(value);
-        }
-    }
-}
+using System;
+using System.IO;
+using Newtonsoft.Json;
+
+namespace Max2Babylon
+{
+    class JsonTextWriterOptimized : JsonTextWriter
+    {
+        public JsonTextWriterOptimized(TextWriter textWriter)
+            : base(textWriter)
+        {
+        }
+        public override void WriteValue(float value)
+        {
+            value = (float)Math.Round(value, 4);
+            base.WriteValue(value);
+        }
+    }
+}

+ 29 - 29
Exporters/3ds Max/Max2Babylon/Loader.cs

@@ -1,29 +1,29 @@
-using System;
-using System.ComponentModel;
-using Autodesk.Max;
-using Autodesk.Max.Plugins;
-
-namespace Max2Babylon
-{
-    public class Loader
-    {
-        public static IGlobal Global;
-        public static IInterface14 Core;
-        public static IClass_ID Class_ID;
-
-        public static void AssemblyMain()
-        {
-            Global = GlobalInterface.Instance;
-            Core = Global.COREInterface14;
-            Class_ID = Global.Class_ID.Create(0x8217f123, 0xef980456);
-            Core.AddClass(new Descriptor());
-        }
-
-        public static void AssemblyShutdown()
-        {
-
-        }
-
-     
-    }
-}
+using System;
+using System.ComponentModel;
+using Autodesk.Max;
+using Autodesk.Max.Plugins;
+
+namespace Max2Babylon
+{
+    public class Loader
+    {
+        public static IGlobal Global;
+        public static IInterface14 Core;
+        public static IClass_ID Class_ID;
+
+        public static void AssemblyMain()
+        {
+            Global = GlobalInterface.Instance;
+            Core = Global.COREInterface14;
+            Class_ID = Global.Class_ID.Create(0x8217f123, 0xef980456);
+            Core.AddClass(new Descriptor());
+        }
+
+        public static void AssemblyShutdown()
+        {
+
+        }
+
+     
+    }
+}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 834 - 834
Exporters/3ds Max/Max2Babylon/Tools/Tools.cs


+ 84 - 84
Exporters/3ds Max/Max2Babylon/Tools/VNormal.cs

@@ -1,84 +1,84 @@
-using Autodesk.Max;
-using SharpDX;
-
-namespace Max2Babylon
-{
-    public class VNormal
-    {
-        Vector3 norm;
-        uint smooth;
-        VNormal next;
-        bool init;
-
-        public VNormal()
-        {
-            smooth = 0;
-            next = null;
-            init = false;
-            norm = new Vector3(0, 0, 0);
-        }
-
-        public VNormal(Vector3 n, uint s)
-        {
-            next = null;
-            init = true;
-            norm = n;
-            smooth = s;
-        }
-
-        public void AddNormal(Vector3 n, uint s)
-        {
-            if (((s & smooth) == 0) && init)
-            {
-                if (next != null)
-                    next.AddNormal(n, s);
-                else
-                {
-                    next = new VNormal(n, s);
-                }
-            }
-            else
-            {
-                norm += n;
-                smooth |= s;
-                init = true;
-            }
-        }
-
-        public IPoint3 GetNormal(uint s)
-        {
-            if (((smooth & s) != 0) || next == null)
-                return norm.ToPoint3();
-
-            return next.GetNormal(s);
-        }
-
-        // Normalize each normal in the list
-        public void Normalize()
-        {
-            VNormal ptr = next;
-            VNormal prev = this;
-
-            while (ptr != null)
-            {
-                if ((ptr.smooth & smooth) != 0)
-                {
-                    norm += ptr.norm;
-                    prev.next = ptr.next;
-                    ptr = prev.next;
-                }
-                else
-                {
-                    prev = ptr;
-                    ptr = ptr.next;
-                }
-            }
-            norm.Normalize();
-
-            if (next != null)
-            {
-                next.Normalize();
-            }
-        }
-    }
-}
+using Autodesk.Max;
+using SharpDX;
+
+namespace Max2Babylon
+{
+    public class VNormal
+    {
+        Vector3 norm;
+        uint smooth;
+        VNormal next;
+        bool init;
+
+        public VNormal()
+        {
+            smooth = 0;
+            next = null;
+            init = false;
+            norm = new Vector3(0, 0, 0);
+        }
+
+        public VNormal(Vector3 n, uint s)
+        {
+            next = null;
+            init = true;
+            norm = n;
+            smooth = s;
+        }
+
+        public void AddNormal(Vector3 n, uint s)
+        {
+            if (((s & smooth) == 0) && init)
+            {
+                if (next != null)
+                    next.AddNormal(n, s);
+                else
+                {
+                    next = new VNormal(n, s);
+                }
+            }
+            else
+            {
+                norm += n;
+                smooth |= s;
+                init = true;
+            }
+        }
+
+        public IPoint3 GetNormal(uint s)
+        {
+            if (((smooth & s) != 0) || next == null)
+                return norm.ToPoint3();
+
+            return next.GetNormal(s);
+        }
+
+        // Normalize each normal in the list
+        public void Normalize()
+        {
+            VNormal ptr = next;
+            VNormal prev = this;
+
+            while (ptr != null)
+            {
+                if ((ptr.smooth & smooth) != 0)
+                {
+                    norm += ptr.norm;
+                    prev.next = ptr.next;
+                    ptr = prev.next;
+                }
+                else
+                {
+                    prev = ptr;
+                    ptr = ptr.next;
+                }
+            }
+            norm.Normalize();
+
+            if (next != null)
+            {
+                next.Normalize();
+            }
+        }
+    }
+}

+ 182 - 182
Exporters/3ds Max/Max2Babylon/Tools/WebServer.cs

@@ -1,182 +1,182 @@
-using System;
-using System.IO;
-using System.Net;
-using System.Text;
-using System.Threading.Tasks;
-using System.Web;
-
-namespace Max2Babylon
-{
-    public static class WebServer
-    {
-        private static readonly HttpListener listener;
-        private static Task runningTask;
-
-        const string HtmlResponseText = @"
-<!doctype html>
-<html>
-
-<head>
-    <title>Babylon.js</title>
-    <script type='text/javascript' src='http://www.babylonjs.com/oimo.js'></script>
-    <script type='text/javascript' src='http://www.babylonjs.com/cannon.js'></script>
-    <script type='text/javascript' src='http://www.babylonjs.com/babylon.js'></script>
-    <style type='text/css'>
-        html, body, div, canvas {
-            width: 100%;
-            height: 100%;
-            padding: 0;
-            margin: 0;
-            overflow: hidden;
-        }
-
-        #debugLayerButton {
-            position: absolute;
-            border: white solid 1px;
-            background: rgba(128, 128, 128, 0.3);
-            color: white;
-            left: 50%;
-            width: 100px;
-            margin-left:-50px;
-            bottom: 10px;
-        }
-    </style>
-</head>
-
-<body>
-    <canvas id='canvas'></canvas>
-    <button id='debugLayerButton'>Debug layer</button>
-    <script type='text/javascript'>
-        var canvas = document.getElementById('canvas');
-        var engine = new BABYLON.Engine(canvas, true);
-       
-        BABYLON.SceneLoader.Load('', '###SCENE###', engine, function (newScene) {
-            newScene.activeCamera.attachControl(canvas);
-
-            engine.runRenderLoop(function() {
-                newScene.render();
-            });
-
-            window.addEventListener('resize', function () {
-                engine.resize();
-            });
-
-            document.getElementById('debugLayerButton').addEventListener('click', function () {
-                if (newScene.debugLayer.isVisible()) {
-                    newScene.debugLayer.hide();
-                } else {
-                    newScene.debugLayer.show();
-                }
-            });
-        });
-    </script>
-</body>
-</html>";
-
-        public const int Port = 45478;
-
-        public static bool IsSupported { get; private set; }
-
-        static WebServer()
-        {
-            try
-            {
-                listener = new HttpListener();
-
-                if (!HttpListener.IsSupported)
-                {
-                    IsSupported = false;
-                    return;
-                }
-
-                listener.Prefixes.Add("http://localhost:" + Port + "/");
-                listener.Start();
-
-
-                runningTask = Task.Run(() => Listen());
-
-                IsSupported = true;
-            }
-            catch
-            {
-                IsSupported = false;
-            }
-        }
-
-        public static string SceneFilename { get; set; }
-        public static string SceneFolder { get; set; }
-        static Random r = new Random();
-        static void Listen()
-        {
-            try
-            {
-                while (listener.IsListening)
-                {
-                    var context = listener.GetContext();
-                    var request = context.Request;
-                    var url = request.Url;
-
-                    context.Response.AddHeader("Cache-Control", "no-cache");
-                    if (string.IsNullOrEmpty(url.LocalPath) || url.LocalPath == "/")
-                    {
-
-                        var responseText = HtmlResponseText.Replace("###SCENE###", SceneFilename+"?once="+r.Next());
-                        WriteResponse(context, responseText);
-                    }
-                    else
-                    {
-                        try
-                        {
-                            var path = Path.Combine(SceneFolder, HttpUtility.UrlDecode(url.PathAndQuery.Substring(1)));
-                            var questionMarkIndex = path.IndexOf("?");
-                            if (questionMarkIndex != -1)
-                            {
-                                path = path.Substring(0, questionMarkIndex);
-                            }
-                            var hashIndex = path.IndexOf("#");
-                            if (hashIndex != -1)
-                            {
-                                path = path.Substring(0, hashIndex);
-                            }
-                            var buffer = File.ReadAllBytes(path);
-                            WriteResponse(context, buffer);
-                        }
-                        catch
-                        {
-                            context.Response.StatusCode = 404;
-                            context.Response.Close();
-                        }
-                    }
-
-                }
-            }
-            catch
-            {
-            }
-        }
-
-        static void WriteResponse(HttpListenerContext context, string s)
-        {
-            WriteResponse(context.Response, s);
-        }
-
-        static void WriteResponse(HttpListenerContext context, byte[] buffer)
-        {
-            WriteResponse(context.Response, buffer);
-        }
-
-        static void WriteResponse(HttpListenerResponse response, string s)
-        {
-            byte[] buffer = Encoding.UTF8.GetBytes(s);
-            WriteResponse(response, buffer);
-        }
-
-        static void WriteResponse(HttpListenerResponse response, byte[] buffer)
-        {
-            response.ContentLength64 = buffer.Length;
-            Stream output = response.OutputStream;
-            output.Write(buffer, 0, buffer.Length);
-            output.Close();
-        }
-    }
-}
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web;
+
+namespace Max2Babylon
+{
+    public static class WebServer
+    {
+        private static readonly HttpListener listener;
+        private static Task runningTask;
+
+        const string HtmlResponseText = @"
+<!doctype html>
+<html>
+
+<head>
+    <title>Babylon.js</title>
+    <script type='text/javascript' src='http://www.babylonjs.com/oimo.js'></script>
+    <script type='text/javascript' src='http://www.babylonjs.com/cannon.js'></script>
+    <script type='text/javascript' src='http://www.babylonjs.com/babylon.js'></script>
+    <style type='text/css'>
+        html, body, div, canvas {
+            width: 100%;
+            height: 100%;
+            padding: 0;
+            margin: 0;
+            overflow: hidden;
+        }
+
+        #debugLayerButton {
+            position: absolute;
+            border: white solid 1px;
+            background: rgba(128, 128, 128, 0.3);
+            color: white;
+            left: 50%;
+            width: 100px;
+            margin-left:-50px;
+            bottom: 10px;
+        }
+    </style>
+</head>
+
+<body>
+    <canvas id='canvas'></canvas>
+    <button id='debugLayerButton'>Debug layer</button>
+    <script type='text/javascript'>
+        var canvas = document.getElementById('canvas');
+        var engine = new BABYLON.Engine(canvas, true);
+       
+        BABYLON.SceneLoader.Load('', '###SCENE###', engine, function (newScene) {
+            newScene.activeCamera.attachControl(canvas);
+
+            engine.runRenderLoop(function() {
+                newScene.render();
+            });
+
+            window.addEventListener('resize', function () {
+                engine.resize();
+            });
+
+            document.getElementById('debugLayerButton').addEventListener('click', function () {
+                if (newScene.debugLayer.isVisible()) {
+                    newScene.debugLayer.hide();
+                } else {
+                    newScene.debugLayer.show();
+                }
+            });
+        });
+    </script>
+</body>
+</html>";
+
+        public const int Port = 45478;
+
+        public static bool IsSupported { get; private set; }
+
+        static WebServer()
+        {
+            try
+            {
+                listener = new HttpListener();
+
+                if (!HttpListener.IsSupported)
+                {
+                    IsSupported = false;
+                    return;
+                }
+
+                listener.Prefixes.Add("http://localhost:" + Port + "/");
+                listener.Start();
+
+
+                runningTask = Task.Run(() => Listen());
+
+                IsSupported = true;
+            }
+            catch
+            {
+                IsSupported = false;
+            }
+        }
+
+        public static string SceneFilename { get; set; }
+        public static string SceneFolder { get; set; }
+        static Random r = new Random();
+        static void Listen()
+        {
+            try
+            {
+                while (listener.IsListening)
+                {
+                    var context = listener.GetContext();
+                    var request = context.Request;
+                    var url = request.Url;
+
+                    context.Response.AddHeader("Cache-Control", "no-cache");
+                    if (string.IsNullOrEmpty(url.LocalPath) || url.LocalPath == "/")
+                    {
+
+                        var responseText = HtmlResponseText.Replace("###SCENE###", SceneFilename+"?once="+r.Next());
+                        WriteResponse(context, responseText);
+                    }
+                    else
+                    {
+                        try
+                        {
+                            var path = Path.Combine(SceneFolder, HttpUtility.UrlDecode(url.PathAndQuery.Substring(1)));
+                            var questionMarkIndex = path.IndexOf("?");
+                            if (questionMarkIndex != -1)
+                            {
+                                path = path.Substring(0, questionMarkIndex);
+                            }
+                            var hashIndex = path.IndexOf("#");
+                            if (hashIndex != -1)
+                            {
+                                path = path.Substring(0, hashIndex);
+                            }
+                            var buffer = File.ReadAllBytes(path);
+                            WriteResponse(context, buffer);
+                        }
+                        catch
+                        {
+                            context.Response.StatusCode = 404;
+                            context.Response.Close();
+                        }
+                    }
+
+                }
+            }
+            catch
+            {
+            }
+        }
+
+        static void WriteResponse(HttpListenerContext context, string s)
+        {
+            WriteResponse(context.Response, s);
+        }
+
+        static void WriteResponse(HttpListenerContext context, byte[] buffer)
+        {
+            WriteResponse(context.Response, buffer);
+        }
+
+        static void WriteResponse(HttpListenerResponse response, string s)
+        {
+            byte[] buffer = Encoding.UTF8.GetBytes(s);
+            WriteResponse(response, buffer);
+        }
+
+        static void WriteResponse(HttpListenerResponse response, byte[] buffer)
+        {
+            response.ContentLength64 = buffer.Length;
+            Stream output = response.OutputStream;
+            output.Write(buffer, 0, buffer.Length);
+            output.Close();
+        }
+    }
+}

+ 3 - 2
Exporters/3ds Max/readme.md

@@ -26,13 +26,14 @@ To export you can use the [Babylon] menu in the main menu bar.
  - Animations: Position, Fov
 - *Lights*
  - Omni / spot / directional / Ambient(Hemispheric)
- - Shadows maps for directional lights (Variance shadow maps can be actived by checking [ABsoulte Map Bias] in light properties)
+ - Shadows maps for directional lights (Variance shadow maps can be actived by checking [Absolute Map Bias] in light properties)
  - Inclusion / exclusion lists
  - Position / direction
  - Intensity
  - Diffuse
  - Specular
- - Animations: Position, Direction, intensity 
+ - Animations: Position, Direction, intensity, diffuse
+ - Range 
 - *Meshes*
  - Visibility
  - Renderable

BIN=BIN
Exporters/Blender/Blender2Babylon-5.0.zip


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 450 - 242
Exporters/Blender/io_export_babylon.py


+ 0 - 122
Exporters/Blender/io_scene_map/__init__.py

@@ -1,122 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8 compliant>
-
-bl_info = {
-    "name": "Quake MAP format",
-    "author": "Campbell Barton",
-    "blender": (2, 57, 0),
-    "location": "File > Export",
-    "description": "Export MAP brushes, nurbs surfaces, "
-                   "lamps and empties as map nodes",
-    "warning": "",
-    "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
-                "Scripts/Import-Export/Quake_MAP",
-    "tracker_url": "",
-    "support": 'OFFICIAL',
-    "category": "Import-Export"}
-
-# To support reload properly, try to access a package var, if it's there, reload everything
-if "bpy" in locals():
-    import imp
-    if "export_map" in locals():
-        imp.reload(export_map)
-
-
-import bpy
-from bpy.props import StringProperty, FloatProperty, BoolProperty
-from bpy_extras.io_utils import ExportHelper
-
-
-class ExportMAP(bpy.types.Operator, ExportHelper):
-    """Export selection to a quake map"""
-    bl_idname = "export_scene.quake_map"
-    bl_label = "Export MAP"
-    bl_options = {'PRESET'}
-
-    filename_ext = ".map"
-    filter_glob = StringProperty(default="*.map", options={'HIDDEN'})
-
-    face_thickness = FloatProperty(
-            name="Face Thickness",
-            description=("Thickness given to geometry which can't be "
-                         "converted into a brush"),
-            min=0.0001, max=10.0,
-            default=0.1,
-            )
-    global_scale = FloatProperty(
-            name="Scale",
-            description="Scale everything by this value",
-            min=0.01, max=1000.0,
-            default=100.0,
-            )
-    grid_snap = BoolProperty(
-            name="Grid Snap",
-            description="Round to whole numbers",
-            default=False,
-            )
-    texture_null = StringProperty(
-            name="Tex Null",
-            description="Texture used when none is assigned",
-            default="NULL",
-            )
-    texture_opts = StringProperty(
-            name="Tex Opts",
-            description="Brush texture options",
-            default='0 0 0 1 1 0 0 0',
-            )
-
-    def execute(self, context):
-        # import math
-        # from mathutils import Matrix
-        if not self.filepath:
-            raise Exception("filepath not set")
-
-        '''
-        global_matrix = Matrix()
-        global_matrix[0][0] = global_matrix[1][1] = global_matrix[2][2] = self.global_scale
-        global_matrix = global_matrix * axis_conversion(to_forward=self.axis_forward, to_up=self.axis_up).to_4x4()
-
-        keywords = self.as_keywords(ignore=("axis_forward", "axis_up", "global_scale", "check_existing", "filter_glob"))
-        keywords["global_matrix"] = global_matrix
-        '''
-
-        keywords = self.as_keywords(ignore=("check_existing", "filter_glob"))
-
-        from . import export_map
-        return export_map.save(self, context, **keywords)
-
-
-def menu_func(self, context):
-    self.layout.operator(ExportMAP.bl_idname, text="Quake MAP (.map)")
-
-
-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()

+ 0 - 508
Exporters/Blender/io_scene_map/export_map.py

@@ -1,508 +0,0 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software Foundation,
-#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# <pep8-80 compliant>
-
-import bpy
-import os
-
-# TODO, make options
-PREF_SCALE = 100
-PREF_FACE_THICK = 0.1
-PREF_GRID_SNAP = False
-# Quake 1/2?
-# Quake 3+?
-PREF_DEF_TEX_OPTS = '0 0 0 1 1 0 0 0'  # not user settable yet
-
-PREF_NULL_TEX = 'NULL'  # not user settable yet
-PREF_INVIS_TEX = 'common/caulk'
-
-
-def face_uv_get(face):
-    """ Workaround 2.5x change.
-    """
-    me = face.id_data
-    uv_faces = me.uv_textures.active
-    if uv_faces:
-        return uv_faces.data[face.index]
-    else:
-        return None
-
-
-def face_material_get(face):
-    me = face.id_data
-    try:
-        return me.materials[face.material_index]
-    except:
-        return None
-
-
-def write_cube2brush(file, faces):
-    """
-    Takes 6 faces and writes a brush,
-    these faces can be from 1 mesh, 1 cube within a mesh of larger cubes
-    Faces could even come from different meshes or be contrived.
-    """
-    # comment only
-    # file.write('// brush "%s", "%s"\n' % (ob.name, ob.data.name))
-    file.write('// brush from cube\n{\n')
-
-    if PREF_GRID_SNAP:
-        format_vec = '( %d %d %d ) '
-    else:
-        format_vec = '( %.8f %.8f %.8f ) '
-
-    for f in faces:
-        # from 4 verts this gets them in reversed order and only 3 of them
-        # 0,1,2,3 -> 2,1,0
-        me = f.id_data  # XXX25
-        for v in f.vertices[:][2::-1]:
-            file.write(format_vec % me.vertices[v].co[:])
-
-        material = face_material_get(f)
-
-        if material and material.game_settings.invisible:
-            file.write(PREF_INVIS_TEX)
-        else:
-            uf = face_uv_get(f)
-
-            image = uf.image if uf else None
-
-            if image:
-                file.write(os.path.splitext(
-                        bpy.path.basename(image.filepath))[0])
-            else:
-                file.write(PREF_NULL_TEX)
-
-        # Texture stuff ignored for now
-        file.write(" %s\n" % PREF_DEF_TEX_OPTS)
-    file.write('}\n')
-
-
-def round_vec(v):
-    if PREF_GRID_SNAP:
-        return v.to_tuple(0)
-    else:
-        return v[:]
-
-
-def write_face2brush(file, face):
-    """
-    takes a face and writes it as a brush
-    each face is a cube/brush
-    """
-
-    if PREF_GRID_SNAP:
-        format_vec = '( %d %d %d ) '
-    else:
-        format_vec = '( %.8f %.8f %.8f ) '
-
-    image_text = PREF_NULL_TEX
-
-    material = face_material_get(face)
-
-    if material and material.game_settings.invisible:
-        image_text = PREF_INVIS_TEX
-    else:
-        uf = face_uv_get(face)
-
-        image = uf.image if uf else None
-
-        if image:
-            image_text = os.path.splitext(bpy.path.basename(image.filepath))[0]
-
-    # reuse face vertices
-    _v = face.id_data.vertices  # XXX25
-    f_vertices = [_v[vi] for vi in face.vertices]
-    del _v  # XXX25
-
-    # original verts as tuples for writing
-    orig_vco = [v.co[:] for v in f_vertices]
-
-    # new verts that give the face a thickness
-    dist = PREF_SCALE * PREF_FACE_THICK
-    new_vco = [round_vec(v.co - (v.normal * dist)) for v in f_vertices]
-    #new_vco = [round_vec(v.co - (face.no * dist)) for v in face]
-
-    file.write('// brush from face\n{\n')
-    # front
-    for co in orig_vco[2::-1]:
-        file.write(format_vec % co)
-    file.write(image_text)
-    # Texture stuff ignored for now
-    file.write(" %s\n" % PREF_DEF_TEX_OPTS)
-
-    for co in new_vco[:3]:
-        file.write(format_vec % co)
-    if uf and uf.use_twoside:
-        file.write(image_text)
-    else:
-        file.write(PREF_INVIS_TEX)
-
-    # Texture stuff ignored for now
-    file.write(" %s\n" % PREF_DEF_TEX_OPTS)
-
-    # sides.
-    if len(orig_vco) == 3:  # Tri, it seemms tri brushes are supported.
-        index_pairs = ((0, 1), (1, 2), (2, 0))
-    else:
-        index_pairs = ((0, 1), (1, 2), (2, 3), (3, 0))
-
-    for i1, i2 in index_pairs:
-        for co in orig_vco[i1], orig_vco[i2], new_vco[i2]:
-            file.write(format_vec % co)
-        file.write(PREF_INVIS_TEX)
-        file.write(" %s\n" % PREF_DEF_TEX_OPTS)
-
-    file.write('}\n')
-
-
-def is_cube_facegroup(faces):
-    """
-    Returns a bool, true if the faces make up a cube
-    """
-    # cube must have 6 faces
-    if len(faces) != 6:
-        # print('1')
-        return False
-
-    # Check for quads and that there are 6 unique verts
-    verts = {}
-    for f in faces:
-        f_v = f.vertices[:]
-        if len(f_v) != 4:
-            return False
-
-        for v in f_v:
-            verts[v] = 0
-
-    if len(verts) != 8:
-        return False
-
-    # Now check that each vert has 3 face users
-    for f in faces:
-        f_v = f.vertices[:]
-        for v in f_v:
-            verts[v] += 1
-
-    for v in verts.values():
-        if v != 3:  # vert has 3 users?
-            return False
-
-    # Could we check for 12 unique edges??, probably not needed.
-    return True
-
-
-def is_tricyl_facegroup(faces):
-    """
-    is the face group a tri cylinder
-    Returns a bool, true if the faces make an extruded tri solid
-    """
-
-    # cube must have 5 faces
-    if len(faces) != 5:
-        #  print('1')
-        return False
-
-    # Check for quads and that there are 6 unique verts
-    verts = {}
-    tottri = 0
-    for f in faces:
-        if len(f.vertices) == 3:
-            tottri += 1
-
-        for vi in f.vertices:
-            verts[vi] = 0
-
-    if len(verts) != 6 or tottri != 2:
-        return False
-
-    # Now check that each vert has 3 face users
-    for f in faces:
-        for vi in f.vertices:
-            verts[vi] += 1
-
-    for v in verts.values():
-        if v != 3:  # vert has 3 users?
-            return False
-
-    # Could we check for 12 unique edges??, probably not needed.
-    return True
-
-
-def write_node_map(file, ob):
-    """
-    Writes the properties of an object (empty in this case)
-    as a MAP node as long as it has the property name - classname
-    returns True/False based on weather a node was written
-    """
-    props = [(p.name, p.value) for p in ob.game.properties]
-
-    IS_MAP_NODE = False
-    for name, value in props:
-        if name == "classname":
-            IS_MAP_NODE = True
-            break
-
-    if not IS_MAP_NODE:
-        return False
-
-    # Write a node
-    file.write('{\n')
-    for name_value in props:
-        file.write('"%s" "%s"\n' % name_value)
-    if PREF_GRID_SNAP:
-        file.write('"origin" "%d %d %d"\n' %
-                   tuple([round(axis * PREF_SCALE)
-                          for axis in ob.matrix_world.to_translation()]))
-    else:
-        file.write('"origin" "%.6f %.6f %.6f"\n' %
-                   tuple([axis * PREF_SCALE
-                          for axis in ob.matrix_world.to_translation()]))
-
-    file.write('}\n')
-    return True
-
-
-def export_map(context, filepath):
-    """
-    pup_block = [\
-    ('Scale:', PREF_SCALE, 1, 1000,
-            'Scale the blender scene by this value.'),\
-    ('Face Width:', PREF_FACE_THICK, 0.01, 10,
-            'Thickness of faces exported as brushes.'),\
-    ('Grid Snap', PREF_GRID_SNAP,
-            'snaps floating point values to whole numbers.'),\
-    'Null Texture',\
-    ('', PREF_NULL_TEX, 1, 128,
-            'Export textureless faces with this texture'),\
-    'Unseen Texture',\
-    ('', PREF_INVIS_TEX, 1, 128,
-            'Export invisible faces with this texture'),\
-    ]
-
-    if not Draw.PupBlock('map export', pup_block):
-        return
-    """
-    import time
-    from mathutils import Matrix
-    from bpy_extras import mesh_utils
-
-    t = time.time()
-    print("Map Exporter 0.0")
-    file = open(filepath, 'w')
-
-    scene = context.scene
-    objects = context.selected_objects
-
-    obs_mesh = []
-    obs_lamp = []
-    obs_surf = []
-    obs_empty = []
-
-    SCALE_MAT = Matrix()
-    SCALE_MAT[0][0] = SCALE_MAT[1][1] = SCALE_MAT[2][2] = PREF_SCALE
-
-    TOTBRUSH = TOTLAMP = TOTNODE = 0
-
-    for ob in objects:
-        type = ob.type
-        if type == 'MESH':
-            obs_mesh.append(ob)
-        elif type == 'SURFACE':
-            obs_surf.append(ob)
-        elif type == 'LAMP':
-            obs_lamp.append(ob)
-        elif type == 'EMPTY':
-            obs_empty.append(ob)
-
-    if obs_mesh or obs_surf:
-        # brushes and surf's must be under worldspan
-        file.write('\n// entity 0\n')
-        file.write('{\n')
-        file.write('"classname" "worldspawn"\n')
-
-    print("\twriting cubes from meshes")
-    for ob in obs_mesh:
-        dummy_mesh = ob.to_mesh(scene, True, 'PREVIEW')
-
-        #print len(mesh_split2connected(dummy_mesh))
-
-        # Is the object 1 cube? - object-is-a-brush
-        # 1 to tx the normals also
-        dummy_mesh.transform(ob.matrix_world * SCALE_MAT)
-
-        if PREF_GRID_SNAP:
-            for v in dummy_mesh.vertices:
-                v.co[:] = v.co.to_tuple(0)
-
-        # High quality normals
-        #XXX25: BPyMesh.meshCalcNormals(dummy_mesh)
-
-        # We need tessfaces
-        dummy_mesh.update(calc_tessface=True)
-
-        # Split mesh into connected regions
-        for face_group in mesh_utils.mesh_linked_tessfaces(dummy_mesh):
-            if is_cube_facegroup(face_group):
-                write_cube2brush(file, face_group)
-                TOTBRUSH += 1
-            elif is_tricyl_facegroup(face_group):
-                write_cube2brush(file, face_group)
-                TOTBRUSH += 1
-            else:
-                for f in face_group:
-                    write_face2brush(file, f)
-                    TOTBRUSH += 1
-
-            #print 'warning, not exporting "%s" it is not a cube' % ob.name
-        bpy.data.meshes.remove(dummy_mesh)
-
-    valid_dims = 3, 5, 7, 9, 11, 13, 15
-    for ob in obs_surf:
-        '''
-        Surf, patches
-        '''
-        data = ob.data
-        surf_name = data.name
-        mat = ob.matrix_world * SCALE_MAT
-
-        # This is what a valid patch looks like
-
-        """
-// brush 0
-{
-patchDef2
-{
-NULL
-( 3 3 0 0 0 )
-(
-( ( -64 -64 0 0 0 ) ( -64 0 0 0 -2 ) ( -64 64 0 0 -4 ) )
-( ( 0 -64 0 2 0 ) ( 0 0 0 2 -2 ) ( 0 64 0 2 -4 ) )
-( ( 64 -64 0 4 0 ) ( 64 0 0 4 -2 ) ( 80 88 0 4 -4 ) )
-)
-}
-}
-        """
-        for i, nurb in enumerate(data.splines):
-            u = nurb.point_count_u
-            v = nurb.point_count_v
-            if u in valid_dims and v in valid_dims:
-
-                file.write('// brush %d surf_name\n' % i)
-                file.write('{\n')
-                file.write('patchDef2\n')
-                file.write('{\n')
-                file.write('NULL\n')
-                file.write('( %d %d 0 0 0 )\n' % (u, v))
-                file.write('(\n')
-
-                u_iter = 0
-                for p in nurb.points:
-
-                    if u_iter == 0:
-                        file.write('(')
-
-                    u_iter += 1
-
-                    # add nmapping 0 0 ?
-                    if PREF_GRID_SNAP:
-                        file.write(" ( %d %d %d 0 0 )" %
-                                   round_vec(mat * p.co.xyz))
-                    else:
-                        file.write(' ( %.6f %.6f %.6f 0 0 )' %
-                                   (mat * p.co.xyz)[:])
-
-                    # Move to next line
-                    if u_iter == u:
-                        file.write(' )\n')
-                        u_iter = 0
-
-                file.write(')\n')
-                file.write('}\n')
-                file.write('}\n')
-                # Debugging
-                # for p in nurb: print 'patch', p
-
-            else:
-                print("Warning: not exporting patch",
-                      surf_name, u, v, 'Unsupported')
-
-    if obs_mesh or obs_surf:
-        file.write('}\n')  # end worldspan
-
-    print("\twriting lamps")
-    for ob in obs_lamp:
-        print("\t\t%s" % ob.name)
-        lamp = ob.data
-        file.write('{\n')
-        file.write('"classname" "light"\n')
-        file.write('"light" "%.6f"\n' % (lamp.distance * PREF_SCALE))
-        if PREF_GRID_SNAP:
-            file.write('"origin" "%d %d %d"\n' %
-                       tuple([round(axis * PREF_SCALE)
-                              for axis in ob.matrix_world.to_translation()]))
-        else:
-            file.write('"origin" "%.6f %.6f %.6f"\n' %
-                       tuple([axis * PREF_SCALE
-                              for axis in ob.matrix_world.to_translation()]))
-
-        file.write('"_color" "%.6f %.6f %.6f"\n' % tuple(lamp.color))
-        file.write('"style" "0"\n')
-        file.write('}\n')
-        TOTLAMP += 1
-
-    print("\twriting empty objects as nodes")
-    for ob in obs_empty:
-        if write_node_map(file, ob):
-            print("\t\t%s" % ob.name)
-            TOTNODE += 1
-        else:
-            print("\t\tignoring %s" % ob.name)
-
-    file.close()
-
-    print("Exported Map in %.4fsec" % (time.time() - t))
-    print("Brushes: %d  Nodes: %d  Lamps %d\n" % (TOTBRUSH, TOTNODE, TOTLAMP))
-
-
-def save(operator,
-         context,
-         filepath=None,
-         global_scale=100.0,
-         face_thickness=0.1,
-         texture_null="NULL",
-         texture_opts='0 0 0 1 1 0 0 0',
-         grid_snap=False,
-         ):
-
-    global PREF_SCALE
-    global PREF_FACE_THICK
-    global PREF_NULL_TEX
-    global PREF_DEF_TEX_OPTS
-    global PREF_GRID_SNAP
-
-    PREF_SCALE = global_scale
-    PREF_FACE_THICK = face_thickness
-    PREF_NULL_TEX = texture_null
-    PREF_DEF_TEX_OPTS = texture_opts
-    PREF_GRID_SNAP = grid_snap
-
-    export_map(context, filepath)
-
-    return {'FINISHED'}

+ 8 - 5
Exporters/Blender/readme.md

@@ -3,7 +3,8 @@ Blender to Babylon.js exporter
 
 The [Blender export plugin](http://blogs.msdn.com/b/eternalcoding/archive/2013/06/28/babylon-js-how-to-load-a-babylon-file-produced-with-blender.aspx) supports the following features:
 
-For a discussion of Tower of Babel exporter, along with the difference this exporter, [See]{https://github.com/BabylonJS/Extensions/tree/master/TowerOfBabel)
+For a discussion of Tower of Babel exporter, along with the difference this exporter, see [ToB readme](https://github.com/BabylonJS/Extensions/tree/master/QueuedInterpolation/Blender).
+
 * **Cameras**
  * Name
  * Position
@@ -14,7 +15,7 @@ For a discussion of Tower of Babel exporter, along with the difference this expo
  * Check collisions
  * Gravity
  * Ellipsoid
- * Animations
+ * Actions exported as AnimationRanges
  * 3D Camera Rigs
  * All kind of Babylon.js cameras can be chosen from a custom dropdown list
 * **Lights**
@@ -27,8 +28,9 @@ For a discussion of Tower of Babel exporter, along with the difference this expo
  * Energy
  * Diffuse color
  * Specular color
+ * Include only meshes in same Blender layer
  * Shadow maps, all types (For directional lights)
- * Animations
+ * Actions exported as AnimationRanges
 * **Materials**
  * Name
  * Name space
@@ -48,6 +50,7 @@ For a discussion of Tower of Babel exporter, along with the difference this expo
  * Procedural Texture Baking
  * Cycles Render Baking
  * Check Ready Only Once
+ * Maximum Simultaneous Lights
 * **Multi-materials**
  * Name
  * Child materials
@@ -77,9 +80,9 @@ For a discussion of Tower of Babel exporter, along with the difference this expo
  * Check collisions
  * Billboard
  * Receive and cast shadows
- * Bones (armatures) and bones' animations
+ * Bones (armatures) and bones' actions
  	* Variable Max Bone Influencers / vertex
- * Animations
+ * Actions exported as AnimationRanges
 
 
 

+ 89 - 0
Exporters/Blender/src/__init__.py

@@ -0,0 +1,89 @@
+bl_info = {
+    'name': 'Babylon.js',
+    'author': 'David Catuhe, Jeff Palmer',
+    'version': (5, 0, 6),
+    'blender': (2, 76, 0),
+    'location': 'File > Export > Babylon.js (.babylon)',
+    'description': 'Export Babylon.js scenes (.babylon)',
+    'wiki_url': 'https://github.com/BabylonJS/Babylon.js/tree/master/Exporters/Blender',
+    'tracker_url': '',
+    'category': 'Babylon.JS'}
+
+# allow module to be changed during a session (dev purposes)
+if "bpy" in locals():
+    print('Reloading TOB exporter')
+    import imp
+    imp.reload(animation)
+    imp.reload(armature)
+    imp.reload(camera)
+    imp.reload(exporter_settings_panel)
+    imp.reload(f_curve_animatable)
+    imp.reload(json_exporter)
+    imp.reload(light_shadow)
+    imp.reload(logger)
+    imp.reload(material)
+    imp.reload(mesh)
+    imp.reload(package_level)
+    imp.reload(sound)
+    imp.reload(world)
+else:
+    from . import animation
+    from . import armature
+    from . import camera
+    from . import exporter_settings_panel
+    from . import f_curve_animatable
+    from . import json_exporter
+    from . import light_shadow
+    from . import logger
+    from . import material
+    from . import mesh
+    from . import package_level
+    from . import sound
+    from . import world
+
+import bpy
+from bpy_extras.io_utils import ExportHelper, ImportHelper
+#===============================================================================
+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)
+
+# Registration the calling of the INFO_MT_file_export file selector
+def menu_func(self, context):
+    from .package_level import get_title
+    # the info for get_title is in this file, but getting it the same way as others
+    self.layout.operator(JsonMain.bl_idname, get_title())
+
+if __name__ == '__main__':
+    unregister()
+    register()
+#===============================================================================
+class JsonMain(bpy.types.Operator, ExportHelper):
+    bl_idname = 'bjs.main'
+    bl_label = 'Export Babylon.js scene' # used on the label of the actual 'save' button
+    filename_ext = '.babylon'            # used as the extension on file selector
+
+    filepath = bpy.props.StringProperty(subtype = 'FILE_PATH') # assigned once the file selector returns
+    
+    def execute(self, context):
+        from .json_exporter import JsonExporter
+        from .package_level import get_title, verify_min_blender_version
+        
+        if not verify_min_blender_version():
+            self.report({'ERROR'}, 'version of Blender too old.')
+            return {'FINISHED'}
+            
+        exporter = JsonExporter()
+        exporter.execute(context, self.filepath)
+        
+        if (exporter.fatalError):
+            self.report({'ERROR'}, exporter.fatalError)
+
+        elif (exporter.nWarnings > 0):
+            self.report({'WARNING'}, 'Processing completed, but ' + str(exporter.nWarnings) + ' WARNINGS were raised,  see log file.')
+            
+        return {'FINISHED'}

+ 174 - 0
Exporters/Blender/src/animation.py

@@ -0,0 +1,174 @@
+from .logger import *
+from .package_level import *
+
+import bpy
+
+FRAME_BASED_ANIMATION = True # turn off for diagnostics; only actual keyframes will be written for skeleton animation
+
+# passed to Animation constructor from animatable objects, defined in BABYLON.Animation
+#ANIMATIONTYPE_FLOAT = 0
+ANIMATIONTYPE_VECTOR3 = 1
+ANIMATIONTYPE_QUATERNION = 2
+ANIMATIONTYPE_MATRIX = 3
+#ANIMATIONTYPE_COLOR3 = 4
+
+# passed to Animation constructor from animatable objects, defined in BABYLON.Animation
+#ANIMATIONLOOPMODE_RELATIVE = 0
+ANIMATIONLOOPMODE_CYCLE = 1
+#ANIMATIONLOOPMODE_CONSTANT = 2
+#===============================================================================
+class AnimationRange:
+    # constructor called by the static actionPrep method
+    def __init__(self, name, frames, frameOffset):
+        # process input args to members
+        self.name = name
+        self.frames_in = frames
+        self.frame_start = AnimationRange.nextStartingFrame(frameOffset)
+
+        self.frames_out = []
+        for frame in self.frames_in:
+            self.frames_out.append(self.frame_start + frame)
+
+        highest_idx = len(self.frames_in) - 1
+        self.highest_frame_in = self.frames_in [highest_idx]
+        self.frame_end        = self.frames_out[highest_idx]
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_string(self):
+        return self.name + ': ' + ' in[' + format_int(self.frames_in[0]) + ' - ' + format_int(self.highest_frame_in) + '], out[' + format_int(self.frame_start) + ' - ' + format_int(self.frame_end) + ']'
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_string(file_handler, 'name', self.name, True)
+        write_int(file_handler, 'from', self.frame_start)
+        write_int(file_handler, 'to', self.frame_end)
+        file_handler.write('}')
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    @staticmethod
+    def actionPrep(object, action, includeAllFrames, frameOffset):
+        # when name in format of object-action, verify object's name matches
+        if action.name.find('-') > 0:
+            split = action.name.partition('-')
+            if split[0] != object.name: return None
+            actionName = split[2]
+        else:
+            actionName = action.name
+
+        # assign the action to the object
+        object.animation_data.action = action
+
+        if includeAllFrames:
+            frame_start = int(action.frame_range[0])
+            frame_end   = int(action.frame_range[1])
+            frames = range(frame_start, frame_end + 1) # range is not inclusive with 2nd arg
+
+        else:
+            # capture built up from fcurves
+            frames = dict()
+            for fcurve in object.animation_data.action.fcurves:
+                for key in fcurve.keyframe_points:
+                    frame = key.co.x
+                    frames[frame] = True
+
+            frames = sorted(frames)
+
+        return AnimationRange(actionName, frames, frameOffset)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    @staticmethod
+    def nextStartingFrame(frameOffset):
+        if frameOffset == 0: return 0
+
+        # ensure a gap of at least 5 frames, starting on an even multiple of 10
+        frameOffset += 4
+        remainder = frameOffset % 10
+        return frameOffset + 10 - remainder
+
+#===============================================================================
+class Animation:
+    def __init__(self, dataType, loopBehavior, name, propertyInBabylon, attrInBlender = None, mult = 1, xOffset = 0):
+        self.dataType = dataType
+        self.framePerSecond = bpy.context.scene.render.fps
+        self.loopBehavior = loopBehavior
+        self.name = name
+        self.propertyInBabylon = propertyInBabylon
+
+        # these never get used by Bones, so optional in contructor args
+        self.attrInBlender = attrInBlender
+        self.mult = mult
+        self.xOffset = xOffset
+
+        #keys
+        self.frames = []
+        self.values = [] # vector3 for ANIMATIONTYPE_VECTOR3 & matrices for ANIMATIONTYPE_MATRIX
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    # a separate method outside of constructor, so can be called once for each Blender Action object participates in
+    def append_range(self, object, animationRange):
+        # action already assigned, always using poses, not every frame, build up again filtering by attrInBlender
+        for idx in range(len(animationRange.frames_in)):
+            bpy.context.scene.frame_set(animationRange.frames_in[idx])
+
+            self.frames.append(animationRange.frames_out[idx])
+            self.values.append(self.get_attr(object))
+
+        return len(animationRange.frames_in) > 0
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    # for auto animate
+    def get_first_frame(self):
+        return self.frames[0] if len(self.frames) > 0 else -1
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    # for auto animate
+    def get_last_frame(self):
+        return self.frames[len(self.frames) - 1] if len(self.frames) > 0 else -1
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_int(file_handler, 'dataType', self.dataType, True)
+        write_int(file_handler, 'framePerSecond', self.framePerSecond)
+
+        file_handler.write(',"keys":[')
+        first = True
+        for frame_idx in range(len(self.frames)):
+            if first != True:
+                file_handler.write(',')
+            first = False
+            file_handler.write('\n{')
+            write_int(file_handler, 'frame', self.frames[frame_idx], True)
+            value_idx = self.values[frame_idx]
+            if self.dataType == ANIMATIONTYPE_MATRIX:
+                write_matrix4(file_handler, 'values', value_idx)
+            elif self.dataType == ANIMATIONTYPE_QUATERNION:
+                write_quaternion(file_handler, 'values', value_idx)
+            else:
+                write_vector(file_handler, 'values', value_idx)
+            file_handler.write('}')
+
+        file_handler.write(']')   # close keys
+
+        # put this at the end to make less crazy looking ]}]]]}}}}}}}]]]],
+        # since animation is also at the end of the bone, mesh, camera, or light
+        write_int(file_handler, 'loopBehavior', self.loopBehavior)
+        write_string(file_handler, 'name', self.name)
+        write_string(file_handler, 'property', self.propertyInBabylon)
+        file_handler.write('}')
+#===============================================================================
+class VectorAnimation(Animation):
+    def __init__(self, object, propertyInBabylon, attrInBlender, mult = 1, xOffset = 0):
+        super().__init__(ANIMATIONTYPE_VECTOR3, ANIMATIONLOOPMODE_CYCLE, propertyInBabylon + ' animation', propertyInBabylon, attrInBlender, mult, xOffset)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def get_attr(self, object):
+        return scale_vector(getattr(object, self.attrInBlender), self.mult, self.xOffset)
+#===============================================================================
+class QuaternionAnimation(Animation):
+    def __init__(self, object, propertyInBabylon, attrInBlender, mult = 1, xOffset = 0):
+        super().__init__(ANIMATIONTYPE_QUATERNION, ANIMATIONLOOPMODE_CYCLE, propertyInBabylon + ' animation', propertyInBabylon, attrInBlender, mult, xOffset)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def get_attr(self, object):
+        return post_rotate_quaternion(getattr(object, self.attrInBlender), self.xOffset)
+#===============================================================================
+class QuaternionToEulerAnimation(Animation):
+    def __init__(self, propertyInBabylon, attrInBlender, mult = 1, xOffset = 0):
+        super().__init__(ANIMATIONTYPE_VECTOR3, ANIMATIONLOOPMODE_CYCLE, propertyInBabylon + ' animation', propertyInBabylon, attrInBlender, mult, Offset)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def get_attr(self, object):
+        quat = getattr(object, self.attrInBlender)
+        eul  = quat.to_euler("XYZ")
+        return scale_vector(eul, self.mult, self.xOffset)

+ 194 - 0
Exporters/Blender/src/armature.py

@@ -0,0 +1,194 @@
+from .animation import *
+from .logger import *
+from .package_level import *
+
+import bpy
+from math import radians
+from mathutils import Vector, Matrix
+
+DEFAULT_LIB_NAME = 'Same as filename'
+#===============================================================================
+class Bone:
+    def __init__(self, bpyBone, bpySkeleton, bonesSoFar):
+        self.index = len(bonesSoFar)
+        Logger.log('processing begun of bone:  ' + bpyBone.name + ', index:  '+ str(self.index), 2)
+        self.name = bpyBone.name
+        self.length = bpyBone.length
+        self.posedBone = bpyBone # record so can be used by get_matrix, called by append_animation_pose
+        self.parentBone = bpyBone.parent
+
+        self.matrix_world = bpySkeleton.matrix_world
+        self.matrix = self.get_bone_matrix()
+
+        self.parentBoneIndex = Skeleton.get_bone(bpyBone.parent.name, bonesSoFar).index if bpyBone.parent else -1
+
+        #animation
+        if (bpySkeleton.animation_data):
+            self.animation = Animation(ANIMATIONTYPE_MATRIX, ANIMATIONLOOPMODE_CYCLE, 'anim', '_matrix')
+            self.previousBoneMatrix = None
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def append_animation_pose(self, frame, force = False):
+        currentBoneMatrix = self.get_bone_matrix()
+
+        if (force or not same_matrix4(currentBoneMatrix, self.previousBoneMatrix)):
+            self.animation.frames.append(frame)
+            self.animation.values.append(currentBoneMatrix)
+            self.previousBoneMatrix = currentBoneMatrix
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def set_rest_pose(self, editBone):
+        self.rest = Bone.get_matrix(editBone, self.matrix_world, True)
+        # used to calc skeleton restDimensions
+        self.restHead = editBone.head
+        self.restTail = editBone.tail
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def get_bone_matrix(self, doParentMult = True):
+        return Bone.get_matrix(self.posedBone, self.matrix_world, doParentMult)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    @staticmethod
+    def get_matrix(bpyBone, matrix_world, doParentMult):
+        SystemMatrix = Matrix.Scale(-1, 4, Vector((0, 0, 1))) * Matrix.Rotation(radians(-90), 4, 'X')
+
+        if (bpyBone.parent and doParentMult):
+            return (SystemMatrix * matrix_world * bpyBone.parent.matrix).inverted() * (SystemMatrix * matrix_world * bpyBone.matrix)
+        else:
+            return SystemMatrix * matrix_world * bpyBone.matrix
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('\n{')
+        write_string(file_handler, 'name', self.name, True)
+        write_int(file_handler, 'index', self.index)
+        write_matrix4(file_handler, 'matrix', self.matrix)
+        write_matrix4(file_handler, 'rest', self.rest)
+        write_int(file_handler, 'parentBoneIndex', self.parentBoneIndex)
+        write_float(file_handler, 'length', self.length)
+
+        #animation
+        if hasattr(self, 'animation'):
+            file_handler.write('\n,"animation":')
+            self.animation.to_scene_file(file_handler)
+
+        file_handler.write('}')
+#===============================================================================
+class Skeleton:
+    # skipAnimations argument only used when exporting QI.SkeletonPoseLibrary
+    def __init__(self, bpySkeleton, scene, id, ignoreIKBones, skipAnimations = False):
+        Logger.log('processing begun of skeleton:  ' + bpySkeleton.name + ', id:  '+ str(id))
+        self.name = bpySkeleton.name
+        self.id = id
+        self.bones = []
+
+        for bone in bpySkeleton.pose.bones:
+            if ignoreIKBones and Skeleton.isIkName(bone.name):
+                Logger.log('Ignoring IK bone:  ' + bone.name, 2)
+                continue
+
+            self.bones.append(Bone(bone, bpySkeleton, self.bones))
+
+        if (bpySkeleton.animation_data and not skipAnimations):
+            self.ranges = []
+            frameOffset = 0
+            for action in bpy.data.actions:
+                # get the range / assigning the action to the object
+                animationRange = AnimationRange.actionPrep(bpySkeleton, action, FRAME_BASED_ANIMATION, frameOffset)
+                if animationRange is None:
+                    continue
+
+                Logger.log('processing action ' + animationRange.to_string(), 2)
+                self.ranges.append(animationRange)
+
+                nFrames = len(animationRange.frames_in)
+                for idx in range(nFrames):
+                    bpy.context.scene.frame_set(animationRange.frames_in[idx])
+                    firstOrLast = idx == 0 or idx == nFrames - 1
+
+                    for bone in self.bones:
+                        bone.append_animation_pose(animationRange.frames_out[idx], firstOrLast)
+
+                frameOffset = animationRange.frame_end
+
+        # mode_set's only work when there is an active object, switch bones to edit mode to rest position
+        scene.objects.active = bpySkeleton
+        bpy.ops.object.mode_set(mode='EDIT')
+
+        # you need to access edit_bones from skeleton.data not skeleton.pose when in edit mode
+        for editBone in bpySkeleton.data.edit_bones:
+            for myBoneObj in self.bones:
+                if editBone.name == myBoneObj.name:
+                    myBoneObj.set_rest_pose(editBone)
+                    break
+
+        self.dimensions = self.getDimensions()
+
+        bpy.ops.object.mode_set(mode='POSE')
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    # do not use .dimensions from blender, it might be including IK bones
+    def getDimensions(self):
+        highest = Vector((-10000, -10000, -10000))
+        lowest  = Vector(( 10000,  10000,  10000))
+
+        for bone in self.bones:
+            if highest.x < bone.restHead.x: highest.x = bone.restHead.x
+            if highest.y < bone.restHead.y: highest.y = bone.restHead.y
+            if highest.z < bone.restHead.z: highest.z = bone.restHead.z
+
+            if highest.x < bone.restTail.x: highest.x = bone.restTail.x
+            if highest.y < bone.restTail.y: highest.y = bone.restTail.y
+            if highest.z < bone.restTail.z: highest.z = bone.restTail.z
+
+            if lowest .x > bone.restHead.x: lowest .x = bone.restHead.x
+            if lowest .y > bone.restHead.y: lowest .y = bone.restHead.y
+            if lowest .z > bone.restHead.z: lowest .z = bone.restHead.z
+
+            if lowest .x > bone.restTail.x: lowest .x = bone.restTail.x
+            if lowest .y > bone.restTail.y: lowest .y = bone.restTail.y
+            if lowest .z > bone.restTail.z: lowest .z = bone.restTail.z
+
+        return Vector((highest.x - lowest.x, highest.y - lowest.y, highest.z - lowest.z))
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    @staticmethod
+    def isIkName(boneName):
+        return '.ik' in boneName.lower() or 'ik.' in boneName.lower()
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    # Since IK bones could be being skipped, looking up index of bone in second pass of mesh required
+    def get_index_of_bone(self, boneName):
+        return Skeleton.get_bone(boneName, self.bones).index
+
+    @staticmethod
+    def get_bone(boneName, bones):
+        for bone in bones:
+            if boneName == bone.name:
+                return bone
+
+        # should not happen, but if it does clearly a bug, so terminate
+        raise Exception('bone name "' + boneName + '" not found in skeleton')
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_string(file_handler, 'name', self.name, True)
+        write_int(file_handler, 'id', self.id)  # keep int for legacy of original exporter
+        write_vector(file_handler, 'dimensionsAtRest', self.dimensions)
+
+        file_handler.write(',"bones":[')
+        first = True
+        for bone in self.bones:
+            if first != True:
+                file_handler.write(',')
+            first = False
+
+            bone.to_scene_file(file_handler)
+
+        file_handler.write(']')
+
+        if hasattr(self, 'ranges'):
+            file_handler.write('\n,"ranges":[')
+            first = True
+            for range in self.ranges:
+                if first != True:
+                    file_handler.write(',')
+                first = False
+
+                range.to_scene_file(file_handler)
+
+            file_handler.write(']')
+
+        file_handler.write('}')

+ 216 - 0
Exporters/Blender/src/camera.py

@@ -0,0 +1,216 @@
+from .logger import *
+from .package_level import *
+
+from .f_curve_animatable import *
+
+import bpy
+import math
+import mathutils
+
+# camera class names, never formally defined in Babylon, but used in babylonFileLoader
+ARC_ROTATE_CAM = 'ArcRotateCamera'
+DEV_ORIENT_CAM = 'DeviceOrientationCamera'
+FOLLOW_CAM = 'FollowCamera'
+FREE_CAM = 'FreeCamera'
+GAMEPAD_CAM = 'GamepadCamera'
+TOUCH_CAM = 'TouchCamera'
+V_JOYSTICKS_CAM = 'VirtualJoysticksCamera'
+VR_DEV_ORIENT_FREE_CAM ='VRDeviceOrientationFreeCamera'
+WEB_VR_FREE_CAM = 'WebVRFreeCamera'
+
+# 3D camera rigs, defined in BABYLON.Camera, must be strings to be in 'dropdown'
+RIG_MODE_NONE = '0'
+RIG_MODE_STEREOSCOPIC_ANAGLYPH = '10'
+RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL = '11'
+RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED = '12'
+RIG_MODE_STEREOSCOPIC_OVERUNDER = '13'
+RIG_MODE_VR = '20'
+#===============================================================================
+class Camera(FCurveAnimatable):
+    def __init__(self, camera):
+        if camera.parent and camera.parent.type != 'ARMATURE':
+            self.parentId = camera.parent.name
+
+        self.CameraType = camera.data.CameraType
+        self.name = camera.name
+        Logger.log('processing begun of camera (' + self.CameraType + '):  ' + self.name)
+        self.define_animations(camera, True, True, False, math.pi / 2)
+        self.position = camera.location
+
+        # for quaternions, convert to euler XYZ, otherwise, use the default rotation_euler
+        eul = camera.rotation_quaternion.to_euler("XYZ") if camera.rotation_mode == 'QUATERNION' else camera.rotation_euler
+        self.rotation = mathutils.Vector((-eul[0] + math.pi / 2, eul[1], -eul[2]))
+
+        self.fov = camera.data.angle
+        self.minZ = camera.data.clip_start
+        self.maxZ = camera.data.clip_end
+        self.speed = 1.0
+        self.inertia = 0.9
+        self.checkCollisions = camera.data.checkCollisions
+        self.applyGravity = camera.data.applyGravity
+        self.ellipsoid = camera.data.ellipsoid
+
+        self.Camera3DRig = camera.data.Camera3DRig
+        self.interaxialDistance = camera.data.interaxialDistance
+
+        for constraint in camera.constraints:
+            if constraint.type == 'TRACK_TO':
+                self.lockedTargetId = constraint.target.name
+                break
+
+
+        if self.CameraType == ARC_ROTATE_CAM or self.CameraType == FOLLOW_CAM:
+            if not hasattr(self, 'lockedTargetId'):
+                Logger.warn('Camera type with manditory target specified, but no target to track set.  Ignored', 2)
+                self.fatalProblem = True
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def update_for_target_attributes(self, meshesAndNodes):
+        if not hasattr(self, 'lockedTargetId'): return
+
+        # find the actual mesh tracking, so properties can be derrived
+        targetFound = False
+        for mesh in meshesAndNodes:
+            if mesh.name == self.lockedTargetId:
+                targetMesh = mesh
+                targetFound = True
+                break;
+
+        xApart = 3 if not targetFound else self.position.x - targetMesh.position.x
+        yApart = 3 if not targetFound else self.position.y - targetMesh.position.y
+        zApart = 3 if not targetFound else self.position.z - targetMesh.position.z
+
+        distance3D = math.sqrt(xApart * xApart + yApart * yApart + zApart * zApart)
+
+        alpha = math.atan2(yApart, xApart);
+        beta  = math.atan2(yApart, zApart);
+
+        if self.CameraType == FOLLOW_CAM:
+            self.followHeight   =  zApart
+            self.followDistance = distance3D
+            self.followRotation =  90 + (alpha * 180 / math.pi)
+
+        elif self.CameraType == self.CameraType == ARC_ROTATE_CAM:
+            self.arcRotAlpha  = alpha
+            self.arcRotBeta   = abs(beta)
+            self.arcRotRadius = distance3D
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_string(file_handler, 'name', self.name, True)
+        write_string(file_handler, 'id', self.name)
+        write_vector(file_handler, 'position', self.position)
+        write_vector(file_handler, 'rotation', self.rotation)
+        write_float(file_handler, 'fov', self.fov)
+        write_float(file_handler, 'minZ', self.minZ)
+        write_float(file_handler, 'maxZ', self.maxZ)
+        write_float(file_handler, 'speed', self.speed)
+        write_float(file_handler, 'inertia', self.inertia)
+        write_bool(file_handler, 'checkCollisions', self.checkCollisions)
+        write_bool(file_handler, 'applyGravity', self.applyGravity)
+        write_array3(file_handler, 'ellipsoid', self.ellipsoid)
+
+        # always assign rig, even when none, Reason:  Could have VR camera with different Rig than default
+        write_int(file_handler, 'cameraRigMode', self.Camera3DRig)
+        write_float(file_handler, 'interaxial_distance', self.interaxialDistance)
+
+        write_string(file_handler, 'type', self.CameraType)
+
+        if hasattr(self, 'parentId'): write_string(file_handler, 'parentId', self.parentId)
+
+        if self.CameraType == FOLLOW_CAM:
+            write_float(file_handler, 'heightOffset',  self.followHeight)
+            write_float(file_handler, 'radius',  self.followDistance)
+            write_float(file_handler, 'rotationOffset',  self.followRotation)
+
+        elif self.CameraType == ARC_ROTATE_CAM:
+            write_float(file_handler, 'alpha', self.arcRotAlpha)
+            write_float(file_handler, 'beta', self.arcRotBeta)
+            write_float(file_handler, 'radius',  self.arcRotRadius)
+
+        if hasattr(self, 'lockedTargetId'):
+            write_string(file_handler, 'lockedTargetId', self.lockedTargetId)
+
+        super().to_scene_file(file_handler) # Animations
+        file_handler.write('}')
+#===============================================================================
+bpy.types.Camera.autoAnimate = bpy.props.BoolProperty(
+    name='Auto launch animations',
+    description='',
+    default = False
+)
+bpy.types.Camera.CameraType = bpy.props.EnumProperty(
+    name='Camera Type',
+    description='',
+    # ONLY Append, or existing .blends will have their camera changed
+    items = (
+             (V_JOYSTICKS_CAM        , 'Virtual Joysticks'       , 'Use Virtual Joysticks Camera'),
+             (TOUCH_CAM              , 'Touch'                   , 'Use Touch Camera'),
+             (GAMEPAD_CAM            , 'Gamepad'                 , 'Use Gamepad Camera'),
+             (FREE_CAM               , 'Free'                    , 'Use Free Camera'),
+             (FOLLOW_CAM             , 'Follow'                  , 'Use Follow Camera'),
+             (DEV_ORIENT_CAM         , 'Device Orientation'      , 'Use Device Orientation Camera'),
+             (ARC_ROTATE_CAM         , 'Arc Rotate'              , 'Use Arc Rotate Camera'),
+             (VR_DEV_ORIENT_FREE_CAM , 'VR Dev Orientation Free' , 'Use VR Dev Orientation Free Camera'),
+             (WEB_VR_FREE_CAM        , 'Web VR Free'             , 'Use Web VR Free Camera')
+            ),
+    default = FREE_CAM
+)
+bpy.types.Camera.checkCollisions = bpy.props.BoolProperty(
+    name='Check Collisions',
+    description='',
+    default = False
+)
+bpy.types.Camera.applyGravity = bpy.props.BoolProperty(
+    name='Apply Gravity',
+    description='',
+    default = False
+)
+bpy.types.Camera.ellipsoid = bpy.props.FloatVectorProperty(
+    name='Ellipsoid',
+    description='',
+    default = mathutils.Vector((0.2, 0.9, 0.2))
+)
+bpy.types.Camera.Camera3DRig = bpy.props.EnumProperty(
+    name='Rig',
+    description='',
+    items = (
+             (RIG_MODE_NONE                             , 'None'                  , 'No 3D effects'),
+             (RIG_MODE_STEREOSCOPIC_ANAGLYPH            , 'Anaaglph'              , 'Stereoscopic Anagylph'),
+             (RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL , 'side-by-side Parallel' , 'Stereoscopic side-by-side parallel'),
+             (RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED, 'side-by-side crosseyed', 'Stereoscopic side-by-side crosseyed'),
+             (RIG_MODE_STEREOSCOPIC_OVERUNDER           , 'over-under'            , 'Stereoscopic over-under'),
+             (RIG_MODE_VR                               , 'VR distortion'         , 'Use Web VR Free Camera')
+            ),
+    default = RIG_MODE_NONE
+)
+bpy.types.Camera.interaxialDistance = bpy.props.FloatProperty(
+    name='Interaxial Distance',
+    description='Distance between cameras.  Used by all but VR 3D rigs.',
+    default = 0.0637
+)
+#===============================================================================
+class CameraPanel(bpy.types.Panel):
+    bl_label = get_title()
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = 'data'
+
+    @classmethod
+    def poll(cls, context):
+        ob = context.object
+        return ob is not None and isinstance(ob.data, bpy.types.Camera)
+
+    def draw(self, context):
+        ob = context.object
+        layout = self.layout
+        layout.prop(ob.data, 'CameraType')
+        layout.prop(ob.data, 'checkCollisions')
+        layout.prop(ob.data, 'applyGravity')
+        layout.prop(ob.data, 'ellipsoid')
+
+        box = layout.box()
+        box.label(text="3D Camera Rigs")
+        box.prop(ob.data, 'Camera3DRig')
+        box.prop(ob.data, 'interaxialDistance')
+
+        layout.prop(ob.data, 'autoAnimate')

+ 70 - 0
Exporters/Blender/src/exporter_settings_panel.py

@@ -0,0 +1,70 @@
+from .package_level import *
+
+import bpy
+# Panel displayed in Scene Tab of properties, so settings can be saved in a .blend file
+class ExporterSettingsPanel(bpy.types.Panel):
+    bl_label = get_title()
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = 'scene'
+
+    bpy.types.Scene.export_onlySelectedLayer = bpy.props.BoolProperty(
+        name="Export only selected layers",
+        description="Export only selected layers",
+        default = False,
+        )
+    bpy.types.Scene.export_flatshadeScene = bpy.props.BoolProperty(
+        name="Flat shade entire scene",
+        description="Use face normals on all meshes.  Increases vertices.",
+        default = False,
+        )
+    bpy.types.Scene.attachedSound = bpy.props.StringProperty(
+        name='Sound',
+        description='',
+        default = ''
+        )
+    bpy.types.Scene.loopSound = bpy.props.BoolProperty(
+        name='Loop sound',
+        description='',
+        default = True
+        )
+    bpy.types.Scene.autoPlaySound = bpy.props.BoolProperty(
+        name='Auto play sound',
+        description='',
+        default = True
+        )
+    bpy.types.Scene.inlineTextures = bpy.props.BoolProperty(
+        name="inline",
+        description="turn textures into encoded strings, for direct inclusion into source code",
+        default = False,
+        )
+    bpy.types.Scene.textureDir = bpy.props.StringProperty(
+        name='sub-directory',
+        description='The path below the output directory to write texture files (any separators OS dependent)',
+        default = ''
+        )
+    bpy.types.Scene.ignoreIKBones = bpy.props.BoolProperty(
+        name="Ignore IK Bones",
+        description="Do not export bones with either '.ik' or 'ik.'(not case sensitive) in the name",
+        default = False,
+        )
+
+    def draw(self, context):
+        layout = self.layout
+
+        scene = context.scene
+        layout.prop(scene, "export_onlySelectedLayer")
+        layout.prop(scene, "export_flatshadeScene")
+        layout.prop(scene, "ignoreIKBones")
+
+        box = layout.box()
+        box.label(text='Texture Location:')
+        box.prop(scene, "inlineTextures")
+        row = box.row()
+        row.enabled = not scene.inlineTextures
+        row.prop(scene, "textureDir")
+
+        box = layout.box()
+        box.prop(scene, 'attachedSound')
+        box.prop(scene, 'autoPlaySound')
+        box.prop(scene, 'loopSound')

+ 105 - 0
Exporters/Blender/src/f_curve_animatable.py

@@ -0,0 +1,105 @@
+from .animation import *
+from .logger import *
+from .package_level import *
+
+import bpy
+#===============================================================================
+class FCurveAnimatable:
+    def define_animations(self, object, supportsRotation, supportsPosition, supportsScaling, xOffsetForRotation = 0):
+
+        # just because a sub-class can be animatable does not mean it is
+        self.animationsPresent = object.animation_data and object.animation_data.action
+
+        if (self.animationsPresent):
+            Logger.log('animation processing begun', 2)
+            # instance each type of animation support regardless of whether there is any data for it
+            if supportsRotation:
+                if object.rotation_mode == 'QUATERNION':
+                    if object.type == 'CAMERA':
+                        # if it's a camera, convert quaternions to euler XYZ
+                        rotAnimation = QuaternionToEulerAnimation(object, 'rotation', 'rotation_quaternion', -1, xOffsetForRotation)
+                    else:
+                        rotAnimation = QuaternionAnimation(object, 'rotationQuaternion', 'rotation_quaternion', 1, xOffsetForRotation)
+                else:
+                    rotAnimation = VectorAnimation(object, 'rotation', 'rotation_euler', -1, xOffsetForRotation)
+
+            if supportsPosition:
+                posAnimation = VectorAnimation(object, 'position', 'location')
+
+            if supportsScaling:
+                scaleAnimation = VectorAnimation(object, 'scaling', 'scale')
+
+            self.ranges = []
+            frameOffset = 0
+
+            currentAction = object.animation_data.action
+            for action in bpy.data.actions:
+                # get the range / assigning the action to the object
+                animationRange = AnimationRange.actionPrep(object, action, False, frameOffset)
+                if animationRange is None:
+                    continue
+
+                if supportsRotation:
+                    hasData = rotAnimation.append_range(object, animationRange)
+
+                if supportsPosition:
+                    hasData |= posAnimation.append_range(object, animationRange)
+
+                if supportsScaling:
+                    hasData |= scaleAnimation.append_range(object, animationRange)
+
+                if hasData:
+                    Logger.log('processing action ' + animationRange.to_string(), 3)
+                    self.ranges.append(animationRange)
+                    frameOffset = animationRange.frame_end
+
+            object.animation_data.action = currentAction
+            #Set Animations
+            self.animations = []
+            if supportsRotation and len(rotAnimation.frames) > 0:
+                 self.animations.append(rotAnimation)
+
+            if supportsPosition and len(posAnimation.frames) > 0:
+                 self.animations.append(posAnimation)
+
+            if supportsScaling and len(scaleAnimation.frames) > 0:
+                 self.animations.append(scaleAnimation)
+
+            if (hasattr(object.data, "autoAnimate") and object.data.autoAnimate):
+                self.autoAnimate = True
+                self.autoAnimateFrom = bpy.context.scene.frame_end
+                self.autoAnimateTo =  0
+                for animation in self.animations:
+                    if self.autoAnimateFrom > animation.get_first_frame():
+                        self.autoAnimateFrom = animation.get_first_frame()
+                    if self.autoAnimateTo < animation.get_last_frame():
+                        self.autoAnimateTo = animation.get_last_frame()
+                self.autoAnimateLoop = True
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        if (self.animationsPresent):
+            file_handler.write('\n,"animations":[')
+            first = True
+            for animation in self.animations:
+                if first == False:
+                    file_handler.write(',')
+                animation.to_scene_file(file_handler)
+                first = False
+            file_handler.write(']')
+
+            file_handler.write(',"ranges":[')
+            first = True
+            for range in self.ranges:
+                if first != True:
+                    file_handler.write(',')
+                first = False
+
+                range.to_scene_file(file_handler)
+
+            file_handler.write(']')
+
+            if (hasattr(self, "autoAnimate") and self.autoAnimate):
+                write_bool(file_handler, 'autoAnimate', self.autoAnimate)
+                write_int(file_handler, 'autoAnimateFrom', self.autoAnimateFrom)
+                write_int(file_handler, 'autoAnimateTo', self.autoAnimateTo)
+                write_bool(file_handler, 'autoAnimateLoop', self.autoAnimateLoop)

+ 297 - 0
Exporters/Blender/src/json_exporter.py

@@ -0,0 +1,297 @@
+from .animation import *
+from .armature import *
+from .camera import *
+from .exporter_settings_panel import *
+from .light_shadow import *
+from .logger import *
+from .material import *
+from .mesh import *
+from .package_level import *
+from .sound import *
+from .world import *
+
+import bpy
+from io import open
+from os import path, makedirs
+#===============================================================================
+class JsonExporter:
+    nameSpace   = None  # assigned in execute
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def execute(self, context, filepath):
+        scene = context.scene
+        self.scene = scene # reference for passing
+        self.fatalError = None
+        try:
+            self.filepathMinusExtension = filepath.rpartition('.')[0]
+            JsonExporter.nameSpace = getNameSpace(self.filepathMinusExtension)
+
+            log = Logger(self.filepathMinusExtension + '.log')
+
+            if bpy.ops.object.mode_set.poll():
+                bpy.ops.object.mode_set(mode = 'OBJECT')
+
+            # assign texture location, purely temporary if inlining
+            self.textureDir = path.dirname(filepath)
+            if not scene.inlineTextures:
+                self.textureDir = path.join(self.textureDir, scene.textureDir)
+                if not path.isdir(self.textureDir):
+                    makedirs(self.textureDir)
+                    Logger.warn("Texture sub-directory did not already exist, created: " + self.textureDir)
+
+            Logger.log('========= Conversion from Blender to Babylon.js =========', 0)
+            Logger.log('Scene settings used:', 1)
+            Logger.log('selected layers only:  ' + format_bool(scene.export_onlySelectedLayer), 2)
+            Logger.log('flat shading entire scene:  ' + format_bool(scene.export_flatshadeScene), 2)
+            Logger.log('inline textures:  ' + format_bool(scene.inlineTextures), 2)
+            if not scene.inlineTextures:
+                Logger.log('texture directory:  ' + self.textureDir, 2)
+
+            self.world = World(scene)
+
+            bpy.ops.screen.animation_cancel()
+            currentFrame = bpy.context.scene.frame_current
+
+            # Active camera
+            if scene.camera != None:
+                self.activeCamera = scene.camera.name
+            else:
+                Logger.warn('No active camera has been assigned, or is not in a currently selected Blender layer')
+
+            self.cameras = []
+            self.lights = []
+            self.shadowGenerators = []
+            self.skeletons = []
+            skeletonId = 0
+            self.meshesAndNodes = []
+            self.materials = []
+            self.multiMaterials = []
+            self.sounds = []
+
+            # Scene level sound
+            if scene.attachedSound != '':
+                self.sounds.append(Sound(scene.attachedSound, scene.autoPlaySound, scene.loopSound))
+
+            # separate loop doing all skeletons, so available in Mesh to make skipping IK bones possible
+            for object in [object for object in scene.objects]:
+                scene.frame_set(currentFrame)
+                if object.type == 'ARMATURE':  #skeleton.pose.bones
+                    if object.is_visible(scene):
+                        self.skeletons.append(Skeleton(object, scene, skeletonId, scene.ignoreIKBones))
+                        skeletonId += 1
+                    else:
+                        Logger.warn('The following armature not visible in scene thus ignored: ' + object.name)
+
+            # exclude lamps in this pass, so ShadowGenerator constructor can be passed meshesAnNodes
+            for object in [object for object in scene.objects]:
+                scene.frame_set(currentFrame)
+                if object.type == 'CAMERA':
+                    if object.is_visible(scene): # no isInSelectedLayer() required, is_visible() handles this for them
+                        self.cameras.append(Camera(object))
+                    else:
+                        Logger.warn('The following camera not visible in scene thus ignored: ' + object.name)
+
+                elif object.type == 'MESH':
+                    forcedParent = None
+                    nameID = ''
+                    nextStartFace = 0
+
+                    while True and self.isInSelectedLayer(object, scene):
+                        mesh = Mesh(object, scene, nextStartFace, forcedParent, nameID, self)
+                        if mesh.hasUnappliedTransforms and hasattr(mesh, 'skeletonWeights'):
+                            self.fatalError = 'Mesh: ' + mesh.name + ' has unapplied transformations.  This will never work for a mesh with an armature.  Export cancelled'
+                            Logger.log(self.fatalError)
+                            return
+
+                        if hasattr(mesh, 'instances'):
+                            self.meshesAndNodes.append(mesh)
+                        else:
+                            break
+
+                        if object.data.attachedSound != '':
+                            self.sounds.append(Sound(object.data.attachedSound, object.data.autoPlaySound, object.data.loopSound, object))
+
+                        nextStartFace = mesh.offsetFace
+                        if nextStartFace == 0:
+                            break
+
+                        if forcedParent is None:
+                            nameID = 0
+                            forcedParent = object
+                            Logger.warn('The following mesh has exceeded the maximum # of vertex elements & will be broken into multiple Babylon meshes: ' + object.name)
+
+                        nameID = nameID + 1
+
+                elif object.type == 'EMPTY':
+                    self.meshesAndNodes.append(Node(object))
+
+                elif object.type != 'LAMP' and object.type != 'ARMATURE':
+                    Logger.warn('The following object (type - ' +  object.type + ') is not currently exportable thus ignored: ' + object.name)
+
+            # Lamp / shadow Generator pass; meshesAnNodes complete & forceParents included
+            for object in [object for object in scene.objects]:
+                if object.type == 'LAMP':
+                    if object.is_visible(scene): # no isInSelectedLayer() required, is_visible() handles this for them
+                        bulb = Light(object, self.meshesAndNodes)
+                        self.lights.append(bulb)
+                        if object.data.shadowMap != 'NONE':
+                            if bulb.light_type == DIRECTIONAL_LIGHT or bulb.light_type == SPOT_LIGHT:
+                                self.shadowGenerators.append(ShadowGenerator(object, self.meshesAndNodes, scene))
+                            else:
+                                Logger.warn('Only directional (sun) and spot types of lamp are valid for shadows thus ignored: ' + object.name)
+                    else:
+                        Logger.warn('The following lamp not visible in scene thus ignored: ' + object.name)
+
+            bpy.context.scene.frame_set(currentFrame)
+
+            # output file
+            self.to_scene_file()
+
+        except:# catch *all* exceptions
+            log.log_error_stack()
+            raise
+
+        finally:
+            log.close()
+
+        self.nWarnings = log.nWarnings
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self):
+        Logger.log('========= Writing of scene file started =========', 0)
+        # Open file
+        file_handler = open(self.filepathMinusExtension + '.babylon', 'w', encoding='utf8')
+        file_handler.write('{')
+        file_handler.write('"producer":{"name":"Blender","version":"' + bpy.app.version_string + '","exporter_version":"' + format_exporter_version() + '","file":"' + JsonExporter.nameSpace + '.babylon"},\n')
+        self.world.to_scene_file(file_handler)
+
+        # Materials
+        file_handler.write(',\n"materials":[')
+        first = True
+        for material in self.materials:
+            if first != True:
+                file_handler.write(',\n')
+
+            first = False
+            material.to_scene_file(file_handler)
+        file_handler.write(']')
+
+        # Multi-materials
+        file_handler.write(',\n"multiMaterials":[')
+        first = True
+        for multimaterial in self.multiMaterials:
+            if first != True:
+                file_handler.write(',')
+
+            first = False
+            multimaterial.to_scene_file(file_handler)
+        file_handler.write(']')
+
+        # Armatures/Bones
+        file_handler.write(',\n"skeletons":[')
+        first = True
+        for skeleton in self.skeletons:
+            if first != True:
+                file_handler.write(',')
+
+            first = False
+            skeleton.to_scene_file(file_handler)
+        file_handler.write(']')
+
+        # Meshes
+        file_handler.write(',\n"meshes":[')
+        first = True
+        for mesh in self.meshesAndNodes:
+            if first != True:
+                file_handler.write(',')
+
+            first = False
+            mesh.to_scene_file(file_handler)
+        file_handler.write(']')
+
+        # Cameras
+        file_handler.write(',\n"cameras":[')
+        first = True
+        for camera in self.cameras:
+            if hasattr(camera, 'fatalProblem'): continue
+            if first != True:
+                file_handler.write(',')
+
+            first = False
+            camera.update_for_target_attributes(self.meshesAndNodes)
+            camera.to_scene_file(file_handler)
+        file_handler.write(']')
+
+        # Active camera
+        if hasattr(self, 'activeCamera'):
+            write_string(file_handler, 'activeCamera', self.activeCamera)
+
+        # Lights
+        file_handler.write(',\n"lights":[')
+        first = True
+        for light in self.lights:
+            if first != True:
+                file_handler.write(',')
+
+            first = False
+            light.to_scene_file(file_handler)
+        file_handler.write(']')
+
+        # Shadow generators
+        file_handler.write(',\n"shadowGenerators":[')
+        first = True
+        for shadowGen in self.shadowGenerators:
+            if first != True:
+                file_handler.write(',')
+
+            first = False
+            shadowGen.to_scene_file(file_handler)
+        file_handler.write(']')
+
+        # Sounds
+        if len(self.sounds) > 0:
+            file_handler.write('\n,"sounds":[')
+            first = True
+            for sound in self.sounds:
+                if first != True:
+                    file_handler.write(',')
+
+                first = False
+                sound.to_scene_file(file_handler)
+
+            file_handler.write(']')
+
+        # Closing
+        file_handler.write('\n}')
+        file_handler.close()
+        Logger.log('========= Writing of scene file completed =========', 0)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def getMaterial(self, baseMaterialId):
+        fullName = JsonExporter.nameSpace + '.' + baseMaterialId
+        for material in self.materials:
+            if material.name == fullName:
+                return material
+
+        return None
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def getSourceMeshInstance(self, dataName):
+        for mesh in self.meshesAndNodes:
+            # nodes have no 'dataName', cannot be instanced in any case
+            if hasattr(mesh, 'dataName') and mesh.dataName == dataName:
+                return mesh
+
+        return None
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def isInSelectedLayer(self, obj, scene):
+        if not scene.export_onlySelectedLayer:
+            return True
+
+        for l in range(0, len(scene.layers)):
+            if obj.layers[l] and scene.layers[l]:
+                return True
+        return False
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def get_skeleton(self, name):
+        for skeleton in self.skeletons:
+            if skeleton.name == name:
+                return skeleton
+        #really cannot happen, will cause exception in caller
+        return None

+ 222 - 0
Exporters/Blender/src/light_shadow.py

@@ -0,0 +1,222 @@
+from .logger import *
+from .package_level import *
+
+from .f_curve_animatable import *
+
+import bpy
+from mathutils import Color, Vector
+
+# used in Light constructor, never formally defined in Babylon, but used in babylonFileLoader
+POINT_LIGHT = 0
+DIRECTIONAL_LIGHT = 1
+SPOT_LIGHT = 2
+HEMI_LIGHT = 3
+
+#used in ShadowGenerators
+NO_SHADOWS = 'NONE'
+STD_SHADOWS = 'STD'
+POISSON_SHADOWS = 'POISSON'
+VARIANCE_SHADOWS = 'VARIANCE'
+BLUR_VARIANCE_SHADOWS = 'BLUR_VARIANCE'
+#===============================================================================
+class Light(FCurveAnimatable):
+    def __init__(self, light, meshesAndNodes):
+        if light.parent and light.parent.type != 'ARMATURE':
+            self.parentId = light.parent.name
+
+        self.name = light.name
+        Logger.log('processing begun of light (' + light.data.type + '):  ' + self.name)
+        self.define_animations(light, False, True, False)
+
+        light_type_items = {'POINT': POINT_LIGHT, 'SUN': DIRECTIONAL_LIGHT, 'SPOT': SPOT_LIGHT, 'HEMI': HEMI_LIGHT, 'AREA': POINT_LIGHT}
+        self.light_type = light_type_items[light.data.type]
+
+        if self.light_type == POINT_LIGHT:
+            self.position = light.location
+            if hasattr(light.data, 'use_sphere'):
+                if light.data.use_sphere:
+                    self.range = light.data.distance
+
+        elif self.light_type == DIRECTIONAL_LIGHT:
+            self.position = light.location
+            self.direction = Light.get_direction(light.matrix_local)
+
+        elif self.light_type == SPOT_LIGHT:
+            self.position = light.location
+            self.direction = Light.get_direction(light.matrix_local)
+            self.angle = light.data.spot_size
+            self.exponent = light.data.spot_blend * 2
+            if light.data.use_sphere:
+                self.range = light.data.distance
+
+        else:
+            # Hemi
+            matrix_local = light.matrix_local.copy()
+            matrix_local.translation = Vector((0, 0, 0))
+            self.direction = (Vector((0, 0, -1)) * matrix_local)
+            self.direction = scale_vector(self.direction, -1)
+            self.groundColor = Color((0, 0, 0))
+
+        self.intensity = light.data.energy
+        self.diffuse   = light.data.color if light.data.use_diffuse  else Color((0, 0, 0))
+        self.specular  = light.data.color if light.data.use_specular else Color((0, 0, 0))
+
+        # inclusion section
+        if light.data.use_own_layer:
+            lampLayer = getLayer(light)
+            self.includedOnlyMeshesIds = []
+            for mesh in meshesAndNodes:
+                if mesh.layer == lampLayer:
+                    self.includedOnlyMeshesIds.append(mesh.name)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    @staticmethod
+    def get_direction(matrix):
+        return (matrix.to_3x3() * Vector((0.0, 0.0, -1.0))).normalized()
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_string(file_handler, 'name', self.name, True)
+        write_string(file_handler, 'id', self.name)
+        write_float(file_handler, 'type', self.light_type)
+
+        if hasattr(self, 'parentId'   ): write_string(file_handler, 'parentId'   , self.parentId   )
+        if hasattr(self, 'position'   ): write_vector(file_handler, 'position'   , self.position   )
+        if hasattr(self, 'direction'  ): write_vector(file_handler, 'direction'  , self.direction  )
+        if hasattr(self, 'angle'      ): write_float (file_handler, 'angle'      , self.angle      )
+        if hasattr(self, 'exponent'   ): write_float (file_handler, 'exponent'   , self.exponent   )
+        if hasattr(self, 'groundColor'): write_color (file_handler, 'groundColor', self.groundColor)
+        if hasattr(self, 'range'      ): write_float (file_handler, 'range'      , self.range      )
+
+        write_float(file_handler, 'intensity', self.intensity)
+        write_color(file_handler, 'diffuse', self.diffuse)
+        write_color(file_handler, 'specular', self.specular)
+
+        if hasattr(self, 'includedOnlyMeshesIds'):
+            file_handler.write(',"includedOnlyMeshesIds":[')
+            first = True
+            for meshId in self.includedOnlyMeshesIds:
+                if first != True:
+                    file_handler.write(',')
+                first = False
+
+                file_handler.write('"' + meshId + '"')
+
+            file_handler.write(']')
+
+
+        super().to_scene_file(file_handler) # Animations
+        file_handler.write('}')
+#===============================================================================
+class ShadowGenerator:
+    def __init__(self, lamp, meshesAndNodes, scene):
+        Logger.log('processing begun of shadows for light:  ' + lamp.name)
+        self.lightId = lamp.name
+        self.mapSize = lamp.data.shadowMapSize
+        self.shadowBias = lamp.data.shadowBias
+
+        if lamp.data.shadowMap == VARIANCE_SHADOWS:
+            self.useVarianceShadowMap = True
+        elif lamp.data.shadowMap == POISSON_SHADOWS:
+            self.usePoissonSampling = True
+        elif lamp.data.shadowMap == BLUR_VARIANCE_SHADOWS:
+            self.useBlurVarianceShadowMap = True
+            self.shadowBlurScale = lamp.data.shadowBlurScale
+            self.shadowBlurBoxOffset = lamp.data.shadowBlurBoxOffset
+
+        # .babylon specific section
+        self.shadowCasters = []
+        for mesh in meshesAndNodes:
+            if (mesh.castShadows):
+                self.shadowCasters.append(mesh.name)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_int(file_handler, 'mapSize', self.mapSize, True)
+        write_string(file_handler, 'lightId', self.lightId)
+        write_float(file_handler, 'bias', self.shadowBias)
+
+        if hasattr(self, 'useVarianceShadowMap') :
+            write_bool(file_handler, 'useVarianceShadowMap', self.useVarianceShadowMap)
+        elif hasattr(self, 'usePoissonSampling'):
+            write_bool(file_handler, 'usePoissonSampling', self.usePoissonSampling)
+        elif hasattr(self, 'useBlurVarianceShadowMap'):
+            write_bool(file_handler, 'useBlurVarianceShadowMap', self.useBlurVarianceShadowMap)
+            write_int(file_handler, 'blurScale', self.shadowBlurScale)
+            write_int(file_handler, 'blurBoxOffset', self.shadowBlurBoxOffset)
+
+        file_handler.write(',"renderList":[')
+        first = True
+        for caster in self.shadowCasters:
+            if first != True:
+                file_handler.write(',')
+            first = False
+
+            file_handler.write('"' + caster + '"')
+
+        file_handler.write(']')
+        file_handler.write('}')
+#===============================================================================
+bpy.types.Lamp.autoAnimate = bpy.props.BoolProperty(
+    name='Auto launch animations',
+    description='',
+    default = False
+)
+bpy.types.Lamp.shadowMap = bpy.props.EnumProperty(
+    name='Shadow Map',
+    description='',
+    items = ((NO_SHADOWS           , 'None'         , 'No Shadow Maps'),
+             (STD_SHADOWS          , 'Standard'     , 'Use Standard Shadow Maps'),
+             (POISSON_SHADOWS      , 'Poisson'      , 'Use Poisson Sampling'),
+             (VARIANCE_SHADOWS     , 'Variance'     , 'Use Variance Shadow Maps'),
+             (BLUR_VARIANCE_SHADOWS, 'Blur Variance', 'Use Blur Variance Shadow Maps')
+            ),
+    default = NO_SHADOWS
+)
+
+bpy.types.Lamp.shadowMapSize = bpy.props.IntProperty(
+    name='Shadow Map Size',
+    description='',
+    default = 512
+)
+bpy.types.Lamp.shadowBias = bpy.props.FloatProperty(
+    name='Shadow Bias',
+    description='',
+    default = 0.00005
+)
+
+bpy.types.Lamp.shadowBlurScale = bpy.props.IntProperty(
+    name='Blur Scale',
+    description='',
+    default = 2
+)
+
+bpy.types.Lamp.shadowBlurBoxOffset = bpy.props.IntProperty(
+    name='Blur Box Offset',
+    description='',
+    default = 0
+)
+#===============================================================================
+class LightPanel(bpy.types.Panel):
+    bl_label = get_title()
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = 'data'
+
+    @classmethod
+    def poll(cls, context):
+        ob = context.object
+        return ob is not None and isinstance(ob.data, bpy.types.Lamp)
+
+    def draw(self, context):
+        ob = context.object
+        layout = self.layout
+        layout.prop(ob.data, 'shadowMap')
+        layout.prop(ob.data, 'shadowMapSize')
+        layout.prop(ob.data, 'shadowBias')
+
+        box = layout.box()
+        box.label(text="Blur Variance Shadows")
+        box.prop(ob.data, 'shadowBlurScale')
+        box.prop(ob.data, 'shadowBlurBoxOffset')
+
+        layout.prop(ob.data, 'autoAnimate')

+ 56 - 0
Exporters/Blender/src/logger.py

@@ -0,0 +1,56 @@
+from .package_level import format_f, format_exporter_version
+
+from bpy import app
+from io import open
+from math import floor
+from time import time
+from sys import exc_info
+from traceback import format_tb
+
+class Logger:
+    instance = None
+
+    def __init__(self, filename):
+        self.start_time = time()
+        self.nWarnings = 0
+
+        self.log_handler = open(filename, 'w', encoding='utf8')
+        self.log_handler.write('Exporter version: ' + format_exporter_version() + ', Blender version: ' + app.version_string + '\n')
+
+        # allow the static methods to log, so instance does not need to be passed everywhere
+        Logger.instance = self
+
+    def log_error_stack(self):
+        ex = exc_info()
+        Logger.log('========= An error was encountered =========', 0)
+        stack = format_tb(ex[2])
+        for line in stack:
+           self.log_handler.write(line) # avoid tabs & extra newlines by not calling log() inside catch
+
+        self.log_handler.write('ERROR:  ' + str(ex[1]) + '\n')
+
+    def close(self):
+        Logger.log('========= end of processing =========', 0)
+        elapsed_time = time() - self.start_time
+        minutes = floor(elapsed_time / 60)
+        seconds = elapsed_time - (minutes * 60)
+        Logger.log('elapsed time:  ' + str(minutes) + ' min, ' + format_f(seconds) + ' secs', 0)
+
+        self.log_handler.close()
+        Logger.instance = None
+
+    @staticmethod
+    def warn(msg, numTabIndent = 1, noNewLine = False):
+        Logger.log('WARNING: ' + msg, numTabIndent, noNewLine)
+        Logger.instance.nWarnings += 1
+
+    @staticmethod
+    def log(msg, numTabIndent = 1, noNewLine = False):
+        # allow code that calls Logger run successfully when not logging
+        if Logger.instance is None: return
+
+        for i in range(numTabIndent):
+            Logger.instance.log_handler.write('\t')
+
+        Logger.instance.log_handler.write(msg)
+        if not noNewLine: Logger.instance.log_handler.write('\n')

+ 577 - 0
Exporters/Blender/src/material.py

@@ -0,0 +1,577 @@
+from .logger import *
+from .package_level import *
+
+import bpy
+from base64 import b64encode
+from mathutils import Color
+from os import path, remove
+from shutil import copy
+from sys import exc_info # for writing errors to log file
+
+# used in Texture constructor, defined in BABYLON.Texture
+CLAMP_ADDRESSMODE = 0
+WRAP_ADDRESSMODE = 1
+MIRROR_ADDRESSMODE = 2
+
+# used in Texture constructor, defined in BABYLON.Texture
+EXPLICIT_MODE = 0
+SPHERICAL_MODE = 1
+#PLANAR_MODE = 2
+CUBIC_MODE = 3
+#PROJECTION_MODE = 4
+#SKYBOX_MODE = 5
+
+DEFAULT_MATERIAL_NAMESPACE = 'Same as Filename'
+#===============================================================================
+class MultiMaterial:
+    def __init__(self, material_slots, idx, nameSpace):
+        self.name = nameSpace + '.' + 'Multimaterial#' + str(idx)
+        Logger.log('processing begun of multimaterial:  ' + self.name, 2)
+        self.material_slots = material_slots
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_string(file_handler, 'name', self.name, True)
+        write_string(file_handler, 'id', self.name)
+
+        file_handler.write(',"materials":[')
+        first = True
+        for material in self.material_slots:
+            if first != True:
+                file_handler.write(',')
+            file_handler.write('"' + material.name +'"')
+            first = False
+        file_handler.write(']')
+        file_handler.write('}')
+#===============================================================================
+class Texture:
+    def __init__(self, slot, level, textureOrImage, mesh, exporter):
+        wasBaked = not hasattr(textureOrImage, 'uv_layer')
+        if wasBaked:
+            image = textureOrImage
+            texture = None
+
+            repeat = False
+            self.hasAlpha = False
+            self.coordinatesIndex = 0
+        else:
+            texture = textureOrImage
+            image = texture.texture.image
+
+            repeat = texture.texture.extension == 'REPEAT'
+            self.hasAlpha = texture.texture.use_alpha
+
+            usingMap = texture.uv_layer
+            if len(usingMap) == 0:
+                usingMap = mesh.data.uv_textures[0].name
+
+            Logger.log('Image texture found, type:  ' + slot + ', mapped using: "' + usingMap + '"', 4)
+            if mesh.data.uv_textures[0].name == usingMap:
+                self.coordinatesIndex = 0
+            elif mesh.data.uv_textures[1].name == usingMap:
+                self.coordinatesIndex = 1
+            else:
+                Logger.warn('Texture is not mapped as UV or UV2, assigned 1', 5)
+                self.coordinatesIndex = 0
+
+        # always write the file out, since base64 encoding is easiest from a file
+        try:
+            imageFilepath = path.normpath(bpy.path.abspath(image.filepath))
+            basename = path.basename(imageFilepath)
+
+            internalImage = image.packed_file or wasBaked
+
+            # when coming from either a packed image or a baked image, then save_render
+            if internalImage:
+                if exporter.scene.inlineTextures:
+                    textureFile = path.join(exporter.textureDir, basename + "temp")
+                else:
+                    textureFile = path.join(exporter.textureDir, basename)
+
+                image.save_render(textureFile)
+
+            # when backed by an actual file, copy to target dir, unless inlining
+            else:
+                textureFile = bpy.path.abspath(image.filepath)
+                if not exporter.scene.inlineTextures:
+                    copy(textureFile, exporter.textureDir)
+        except:
+            ex = exc_info()
+            Logger.warn('Error encountered processing image file:  ' + ', Error:  '+ str(ex[1]))
+
+        if exporter.scene.inlineTextures:
+            # base64 is easiest from a file, so sometimes a temp file was made above;  need to delete those
+            with open(textureFile, "rb") as image_file:
+                asString = b64encode(image_file.read()).decode()
+            self.encoded_URI = 'data:image/' + image.file_format + ';base64,' + asString
+
+            if internalImage:
+                remove(textureFile)
+
+        # capture texture attributes
+        self.slot = slot
+        self.name = basename
+        self.level = level
+
+        if (texture and texture.mapping == 'CUBE'):
+            self.coordinatesMode = CUBIC_MODE
+        if (texture and texture.mapping == 'SPHERE'):
+            self.coordinatesMode = SPHERICAL_MODE
+        else:
+            self.coordinatesMode = EXPLICIT_MODE
+
+        self.uOffset = texture.offset.x if texture else 0.0
+        self.vOffset = texture.offset.y if texture else 0.0
+        self.uScale  = texture.scale.x  if texture else 1.0
+        self.vScale  = texture.scale.y  if texture else 1.0
+        self.uAng = 0
+        self.vAng = 0
+        self.wAng = 0
+
+        if (repeat):
+            if (texture.texture.use_mirror_x):
+                self.wrapU = MIRROR_ADDRESSMODE
+            else:
+                self.wrapU = WRAP_ADDRESSMODE
+
+            if (texture.texture.use_mirror_y):
+                self.wrapV = MIRROR_ADDRESSMODE
+            else:
+                self.wrapV = WRAP_ADDRESSMODE
+        else:
+            self.wrapU = CLAMP_ADDRESSMODE
+            self.wrapV = CLAMP_ADDRESSMODE
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write(', \n"' + self.slot + '":{')
+        write_string(file_handler, 'name', self.name, True)
+        write_float(file_handler, 'level', self.level)
+        write_float(file_handler, 'hasAlpha', self.hasAlpha)
+        write_int(file_handler, 'coordinatesMode', self.coordinatesMode)
+        write_float(file_handler, 'uOffset', self.uOffset)
+        write_float(file_handler, 'vOffset', self.vOffset)
+        write_float(file_handler, 'uScale', self.uScale)
+        write_float(file_handler, 'vScale', self.vScale)
+        write_float(file_handler, 'uAng', self.uAng)
+        write_float(file_handler, 'vAng', self.vAng)
+        write_float(file_handler, 'wAng', self.wAng)
+        write_int(file_handler, 'wrapU', self.wrapU)
+        write_int(file_handler, 'wrapV', self.wrapV)
+        write_int(file_handler, 'coordinatesIndex', self.coordinatesIndex)
+        if hasattr(self,'encoded_URI'):
+            write_string(file_handler, 'base64String', self.encoded_URI)
+        file_handler.write('}')
+#===============================================================================
+# need to evaluate the need to bake a mesh before even starting; class also stores specific types of bakes
+class BakingRecipe:
+    def __init__(self, mesh):
+        # transfer from Mesh custom properties
+        self.bakeSize    = mesh.data.bakeSize
+        self.bakeQuality = mesh.data.bakeQuality # for lossy compression formats
+        self.forceBaking = mesh.data.forceBaking # in mesh, but not currently exposed
+        self.usePNG      = mesh.data.usePNG      # in mesh, but not currently exposed
+
+        # initialize all members
+        self.needsBaking      = self.forceBaking
+        self.diffuseBaking    = self.forceBaking
+        self.ambientBaking    = False
+        self.opacityBaking    = False
+        self.reflectionBaking = False
+        self.emissiveBaking   = False
+        self.bumpBaking       = False
+        self.specularBaking   = False
+
+        # need to make sure a single render
+        self.cyclesRender     = False
+        blenderRender         = False
+
+        # accumulators set by Blender Game
+        self.backFaceCulling = True  # used only when baking
+        self.isBillboard = len(mesh.material_slots) == 1 and mesh.material_slots[0].material.game_settings.face_orientation == 'BILLBOARD'
+
+        # Cycles specific, need to get the node trees of each material
+        self.nodeTrees = []
+
+        for material_slot in mesh.material_slots:
+            # a material slot is not a reference to an actual material; need to look up
+            material = material_slot.material
+
+            self.backFaceCulling &= material.game_settings.use_backface_culling
+
+            # testing for Cycles renderer has to be different
+            if material.use_nodes == True:
+                self.needsBaking = True
+                self.cyclesRender = True
+                self.nodeTrees.append(material.node_tree)
+
+                for node in material.node_tree.nodes:
+                    id = node.bl_idname
+                    if id == 'ShaderNodeBsdfDiffuse':
+                        self.diffuseBaking = True
+
+                    if id == 'ShaderNodeAmbientOcclusion':
+                        self.ambientBaking = True
+
+                    # there is no opacity baking for Cycles AFAIK
+                    if id == '':
+                        self.opacityBaking = True
+
+                    if id == 'ShaderNodeEmission':
+                        self.emissiveBaking = True
+
+                    if id == 'ShaderNodeNormal' or id == 'ShaderNodeNormalMap':
+                        self.bumpBaking = True
+
+                    if id == '':
+                        self.specularBaking = True
+
+            else:
+                blenderRender = True
+                nDiffuseImages = 0
+                nReflectionImages = 0
+                nAmbientImages = 0
+                nOpacityImages = 0
+                nEmissiveImages = 0
+                nBumpImages = 0
+                nSpecularImages = 0
+
+                textures = [mtex for mtex in material.texture_slots if mtex and mtex.texture]
+                for mtex in textures:
+                    # ignore empty slots
+                    if mtex.texture.type == 'NONE':
+                        continue
+
+                    # for images, just need to make sure there is only 1 per type
+                    if mtex.texture.type == 'IMAGE' and not self.forceBaking:
+                        if mtex.use_map_diffuse or mtex.use_map_color_diffuse:
+                            if mtex.texture_coords == 'REFLECTION':
+                                nReflectionImages += 1
+                            else:
+                                nDiffuseImages += 1
+
+                        if mtex.use_map_ambient:
+                            nAmbientImages += 1
+
+                        if mtex.use_map_alpha:
+                            nOpacityImages += 1
+
+                        if mtex.use_map_emit:
+                            nEmissiveImages += 1
+
+                        if mtex.use_map_normal:
+                            nBumpImages += 1
+
+                        if mtex.use_map_color_spec:
+                            nSpecularImages += 1
+
+                    else:
+                        self.needsBaking = True
+
+                        if mtex.use_map_diffuse or mtex.use_map_color_diffuse:
+                            if mtex.texture_coords == 'REFLECTION':
+                                self.reflectionBaking = True
+                            else:
+                                self.diffuseBaking = True
+
+                        if mtex.use_map_ambient:
+                            self.ambientBaking = True
+
+                        if mtex.use_map_alpha and material.alpha > 0:
+                            self.opacityBaking = True
+
+                        if mtex.use_map_emit:
+                            self.emissiveBaking = True
+
+                        if mtex.use_map_normal:
+                            self.bumpBaking = True
+
+                        if mtex.use_map_color_spec:
+                            self.specularBaking = True
+
+                # 2nd pass 2 check for multiples of a given image type
+                if nDiffuseImages > 1:
+                    self.needsBaking = self.diffuseBaking = True
+                if nReflectionImages > 1:
+                    self.needsBaking = self.nReflectionImages = True
+                if nAmbientImages > 1:
+                    self.needsBaking = self.ambientBaking = True
+                if nOpacityImages > 1:
+                    self.needsBaking = self.opacityBaking = True
+                if nEmissiveImages > 1:
+                    self.needsBaking = self.emissiveBaking = True
+                if nBumpImages > 1:
+                    self.needsBaking = self.bumpBaking = True
+                if nSpecularImages > 1:
+                    self.needsBaking = self.specularBaking = True
+
+        self.multipleRenders = blenderRender and self.cyclesRender
+
+        # check for really old .blend file, eg. 2.49, to ensure that everything requires exists
+        if self.needsBaking and bpy.data.screens.find('UV Editing') == -1:
+            Logger.warn('Contains material requiring baking, but resources not available.  Probably .blend very old', 2)
+            self.needsBaking = False
+#===============================================================================
+# Not intended to be instanced directly
+class Material:
+    def __init__(self, checkReadyOnlyOnce, maxSimultaneousLights):
+        self.checkReadyOnlyOnce = checkReadyOnlyOnce
+        self.maxSimultaneousLights = maxSimultaneousLights
+        # first pass of textures, either appending image type or recording types of bakes to do
+        self.textures = []
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_string(file_handler, 'name', self.name, True)
+        write_string(file_handler, 'id', self.name)
+        write_color(file_handler, 'ambient', self.ambient)
+        write_color(file_handler, 'diffuse', self.diffuse)
+        write_color(file_handler, 'specular', self.specular)
+        write_color(file_handler, 'emissive', self.emissive)
+        write_float(file_handler, 'specularPower', self.specularPower)
+        write_float(file_handler, 'alpha', self.alpha)
+        write_bool(file_handler, 'backFaceCulling', self.backFaceCulling)
+        write_bool(file_handler, 'checkReadyOnlyOnce', self.checkReadyOnlyOnce)
+        write_int(file_handler, 'maxSimultaneousLights', self.maxSimultaneousLights)
+        for texSlot in self.textures:
+            texSlot.to_scene_file(file_handler)
+
+        file_handler.write('}')
+#===============================================================================
+class StdMaterial(Material):
+    def __init__(self, material_slot, exporter, mesh):
+        super().__init__(mesh.data.checkReadyOnlyOnce, mesh.data.maxSimultaneousLights)
+        nameSpace = exporter.nameSpace if mesh.data.materialNameSpace == DEFAULT_MATERIAL_NAMESPACE or len(mesh.data.materialNameSpace) == 0 else mesh.data.materialNameSpace
+        self.name = nameSpace + '.' + material_slot.name
+
+        Logger.log('processing begun of Standard material:  ' +  material_slot.name, 2)
+
+        # a material slot is not a reference to an actual material; need to look up
+        material = material_slot.material
+
+        self.ambient = material.ambient * material.diffuse_color
+        self.diffuse = material.diffuse_intensity * material.diffuse_color
+        self.specular = material.specular_intensity * material.specular_color
+        self.emissive = material.emit * material.diffuse_color
+        self.specularPower = material.specular_hardness
+        self.alpha = material.alpha
+
+        self.backFaceCulling = material.game_settings.use_backface_culling
+
+        textures = [mtex for mtex in material.texture_slots if mtex and mtex.texture]
+        for mtex in textures:
+            # test should be un-neccessary, since should be a BakedMaterial; just for completeness
+            if (mtex.texture.type != 'IMAGE'):
+                continue
+            elif not mtex.texture.image:
+                Logger.warn('Material has un-assigned image texture:  "' + mtex.name + '" ignored', 3)
+                continue
+            elif len(mesh.data.uv_textures) == 0:
+                Logger.warn('Mesh has no UV maps, material:  "' + mtex.name + '" ignored', 3)
+                continue
+
+            if mtex.use_map_diffuse or mtex.use_map_color_diffuse:
+                if mtex.texture_coords == 'REFLECTION':
+                    Logger.log('Reflection texture found "' + mtex.name + '"', 3)
+                    self.textures.append(Texture('reflectionTexture', mtex.diffuse_color_factor, mtex, mesh, exporter))
+                else:
+                    Logger.log('Diffuse texture found "' + mtex.name + '"', 3)
+                    self.textures.append(Texture('diffuseTexture', mtex.diffuse_color_factor, mtex, mesh, exporter))
+
+            if mtex.use_map_ambient:
+                Logger.log('Ambient texture found "' + mtex.name + '"', 3)
+                self.textures.append(Texture('ambientTexture', mtex.ambient_factor, mtex, mesh, exporter))
+
+            if mtex.use_map_alpha:
+                if self.alpha > 0:
+                    Logger.log('Opacity texture found "' + mtex.name + '"', 3)
+                    self.textures.append(Texture('opacityTexture', mtex.alpha_factor, mtex, mesh, exporter))
+                else:
+                    Logger.warn('Opacity non-std way to indicate opacity, use material alpha to also use Opacity texture', 4)
+                    self.alpha = 1
+
+            if mtex.use_map_emit:
+                Logger.log('Emissive texture found "' + mtex.name + '"', 3)
+                self.textures.append(Texture('emissiveTexture', mtex.emit_factor, mtex, mesh, exporter))
+
+            if mtex.use_map_normal:
+                Logger.log('Bump texture found "' + mtex.name + '"', 3)
+                self.textures.append(Texture('bumpTexture', 1.0 / mtex.normal_factor, mtex, mesh, exporter))
+
+            if mtex.use_map_color_spec:
+                Logger.log('Specular texture found "' + mtex.name + '"', 3)
+                self.textures.append(Texture('specularTexture', mtex.specular_color_factor, mtex, mesh, exporter))
+#===============================================================================
+class BakedMaterial(Material):
+    def __init__(self, exporter, mesh, recipe):
+        super().__init__(mesh.data.checkReadyOnlyOnce, mesh.data.maxSimultaneousLights)
+        nameSpace = exporter.nameSpace if mesh.data.materialNameSpace == DEFAULT_MATERIAL_NAMESPACE or len(mesh.data.materialNameSpace) == 0 else mesh.data.materialNameSpace
+        self.name = nameSpace + '.' + mesh.name
+        Logger.log('processing begun of baked material:  ' +  mesh.name, 2)
+
+        # changes to cycles & smart_project occurred in 2.77; need to know what we are running
+        bVersion = blenderMajorMinorVersion()
+
+        # any baking already took in the values. Do not want to apply them again, but want shadows to show.
+        # These are the default values from StandardMaterials
+        self.ambient = Color((0, 0, 0))
+        self.diffuse = Color((0.8, 0.8, 0.8)) # needed for shadows, but not change anything else
+        self.specular = Color((1, 1, 1))
+        self.emissive = Color((0, 0, 0))
+        self.specularPower = 64
+        self.alpha = 1.0
+
+        self.backFaceCulling = recipe.backFaceCulling
+
+        # texture is baked from selected mesh(es), need to insure this mesh is only one selected
+        bpy.ops.object.select_all(action='DESELECT')
+        mesh.select = True
+
+        # store setting to restore
+        engine = exporter.scene.render.engine
+
+        # mode_set's only work when there is an active object
+        exporter.scene.objects.active = mesh
+
+         # UV unwrap operates on mesh in only edit mode, procedurals can also give error of 'no images to be found' when not done
+         # select all verticies of mesh, since smart_project works only with selected verticies
+        bpy.ops.object.mode_set(mode='EDIT')
+        bpy.ops.mesh.select_all(action='SELECT')
+
+        # you need UV on a mesh in order to bake image.  This is not reqd for procedural textures, so may not exist
+        # need to look if it might already be created, if so use the first one
+        uv = mesh.data.uv_textures[0] if len(mesh.data.uv_textures) > 0 else None
+
+        if uv == None or recipe.forceBaking:
+            mesh.data.uv_textures.new('BakingUV')
+            uv = mesh.data.uv_textures['BakingUV']
+            uv.active = True
+            uv.active_render = not recipe.forceBaking # want the other uv's for the source when combining
+
+            if bVersion <= 2.76:
+                bpy.ops.uv.smart_project(angle_limit = 66.0, island_margin = 0.0, user_area_weight = 1.0, use_aspect = True)
+            else:
+                bpy.ops.uv.smart_project(angle_limit = 66.0, island_margin = 0.0, user_area_weight = 1.0, use_aspect = True, stretch_to_bounds = True)
+
+            # syntax for using unwrap enstead of smart project
+#            bpy.ops.uv.unwrap(margin = 1.0) # defaulting on all
+            uvName = 'BakingUV'  # issues with cycles when not done this way
+        else:
+            uvName = uv.name
+
+        format = 'PNG' if recipe.usePNG else 'JPEG'
+
+        # create a temporary image & link it to the UV/Image Editor so bake_image works
+        image = bpy.data.images.new(name = mesh.name + '_BJS_BAKE', width = recipe.bakeSize, height = recipe.bakeSize, alpha = recipe.usePNG, float_buffer = False)
+        image.file_format = format
+        image.mapping = 'UV' # default value
+
+        image_settings = exporter.scene.render.image_settings
+        image_settings.file_format = format
+        image_settings.color_mode = 'RGBA' if recipe.usePNG else 'RGB'
+        image_settings.quality = recipe.bakeQuality # for lossy compression formats
+        image_settings.compression = recipe.bakeQuality  # Amount of time to determine best compression: 0 = no compression with fast file output, 100 = maximum lossless compression with slow file output
+
+        # now go thru all the textures that need to be baked
+        if recipe.diffuseBaking:
+            cycles_type = 'DIFFUSE_COLOR' if bVersion <= 2.76 else 'DIFFUSE'
+            self.bake('diffuseTexture', cycles_type, 'TEXTURE', image, mesh, uvName, exporter, recipe)
+
+        if recipe.ambientBaking:
+            self.bake('ambientTexture', 'AO', 'AO', image, mesh, uvName, exporter, recipe)
+
+        if recipe.opacityBaking:  # no eqivalent found for cycles
+            self.bake('opacityTexture', None, 'ALPHA', image, mesh, uvName, exporter, recipe)
+
+        if recipe.reflectionBaking:  # no eqivalent found for cycles
+            self.bake('reflectionTexture', None, 'MIRROR_COLOR', image, mesh, uvName, exporter, recipe)
+
+        if recipe.emissiveBaking:
+            self.bake('emissiveTexture', 'EMIT', 'EMIT', image, mesh, uvName, exporter, recipe)
+
+        if recipe.bumpBaking:
+            self.bake('bumpTexture', 'NORMAL', 'NORMALS', image, mesh, uvName, exporter, recipe)
+
+        if recipe.specularBaking:
+            cycles_type = 'SPECULAR' if bVersion <= 2.76 else 'GLOSSY'
+            self.bake('specularTexture', cycles_type, 'SPEC_COLOR', image, mesh, uvName, exporter, recipe)
+
+        # Toggle vertex selection & mode, if setting changed their value
+        bpy.ops.mesh.select_all(action='TOGGLE')  # still in edit mode toggle select back to previous
+        bpy.ops.object.mode_set(toggle=True)      # change back to Object
+
+        bpy.ops.object.select_all(action='TOGGLE') # change scene selection back, not seeming to work
+
+        exporter.scene.render.engine = engine
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def bake(self, bjs_type, cycles_type, internal_type, image, mesh, uvName, exporter, recipe):
+        extension = '.png' if recipe.usePNG else '.jpg'
+
+        if recipe.cyclesRender:
+            if cycles_type is None:
+                return
+            self.bakeCycles(cycles_type, image, uvName, recipe.nodeTrees, extension)
+        else:
+            self.bakeInternal(internal_type, image, uvName, extension)
+
+        self.textures.append(Texture(bjs_type, 1.0, image, mesh, exporter))
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def bakeInternal(self, bake_type, image, uvName, extension):
+        Logger.log('Internal baking texture, type: ' + bake_type + ', mapped using: ' + uvName, 3)
+        # need to use the legal name, since this will become the file name, chars like ':' not legal
+        legalName = legal_js_identifier(self.name)
+        image.filepath = legalName + '_' + bake_type + extension
+
+        scene = bpy.context.scene
+        scene.render.engine = 'BLENDER_RENDER'
+
+        scene.render.bake_type = bake_type
+
+        # assign the image to the UV Editor, which does not have to shown
+        bpy.data.screens['UV Editing'].areas[1].spaces[0].image = image
+
+        renderer = scene.render
+        renderer.use_bake_selected_to_active = False
+        renderer.use_bake_to_vertex_color = False
+        renderer.use_bake_clear = False
+        renderer.bake_quad_split = 'AUTO'
+        renderer.bake_margin = 5
+        renderer.use_file_extension = True
+
+        renderer.use_bake_normalize = True
+        renderer.use_bake_antialiasing = True
+
+        bpy.ops.object.bake_image()
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def bakeCycles(self, bake_type, image, uvName, nodeTrees, extension):
+        Logger.log('Cycles baking texture, type: ' + bake_type + ', mapped using: ' + uvName, 3)
+        legalName = legal_js_identifier(self.name)
+        image.filepath = legalName + '_' + bake_type + extension
+
+        scene = bpy.context.scene
+        scene.render.engine = 'CYCLES'
+
+        # create an unlinked temporary node to bake to for each material
+        for tree in nodeTrees:
+            bakeNode = tree.nodes.new(type='ShaderNodeTexImage')
+            bakeNode.image = image
+            bakeNode.select = True
+            tree.nodes.active = bakeNode
+
+        bpy.ops.object.bake(type = bake_type, use_clear = True, margin = 5, use_selected_to_active = False)
+
+        for tree in nodeTrees:
+            tree.nodes.remove(tree.nodes.active)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    @staticmethod
+    def meshBakingClean(mesh):
+        for uvMap in mesh.data.uv_textures:
+            if uvMap.name == 'BakingUV':
+                mesh.data.uv_textures.remove(uvMap)
+                break
+
+        # remove an image if it was baked
+        for image in bpy.data.images:
+            if image.name == mesh.name + '_BJS_BAKE':
+                image.user_clear() # cannot remove image unless 0 references
+                bpy.data.images.remove(image)
+                break

+ 850 - 0
Exporters/Blender/src/mesh.py

@@ -0,0 +1,850 @@
+from .logger import *
+from .package_level import *
+
+from .f_curve_animatable import *
+from .armature import *
+from .material import *
+
+import bpy
+import math
+from mathutils import Vector
+import shutil
+
+# output related constants
+MAX_VERTEX_ELEMENTS = 65535
+MAX_VERTEX_ELEMENTS_32Bit = 16777216
+COMPRESS_MATRIX_INDICES = True # this is True for .babylon exporter & False for TOB
+
+# used in Mesh & Node constructors, defined in BABYLON.AbstractMesh
+BILLBOARDMODE_NONE = 0
+#BILLBOARDMODE_X = 1
+#BILLBOARDMODE_Y = 2
+#BILLBOARDMODE_Z = 4
+BILLBOARDMODE_ALL = 7
+
+# used in Mesh constructor, defined in BABYLON.PhysicsEngine
+SPHERE_IMPOSTER = 1
+BOX_IMPOSTER = 2
+#PLANE_IMPOSTER = 3
+MESH_IMPOSTER = 4
+CAPSULE_IMPOSTER = 5
+CONE_IMPOSTER = 6
+CYLINDER_IMPOSTER = 7
+CONVEX_HULL_IMPOSTER = 8
+#===============================================================================
+class Mesh(FCurveAnimatable):
+    def __init__(self, object, scene, startFace, forcedParent, nameID, exporter):
+        self.name = object.name + str(nameID)
+        Logger.log('processing begun of mesh:  ' + self.name)
+        self.define_animations(object, True, True, True)  #Should animations be done when forcedParent
+
+        self.isVisible = not object.hide_render
+        self.isEnabled = not object.data.loadDisabled
+        useFlatShading = scene.export_flatshadeScene or object.data.useFlatShading
+        self.checkCollisions = object.data.checkCollisions
+        self.receiveShadows = object.data.receiveShadows
+        self.castShadows = object.data.castShadows
+        self.freezeWorldMatrix = object.data.freezeWorldMatrix
+        self.layer = getLayer(object) # used only for lights with 'This Layer Only' checked, not exported
+
+        # hasSkeleton detection & skeletonID determination
+        hasSkeleton = False
+        objArmature = None      # if there's an armature, this will be the one!
+        if len(object.vertex_groups) > 0 and not object.data.ignoreSkeleton:
+            objArmature = object.find_armature()
+            if objArmature != None:
+                hasSkeleton = True
+                # used to get bone index, since could be skipping IK bones
+                skeleton = exporter.get_skeleton(objArmature.name)
+                i = 0
+                for obj in scene.objects:
+                    if obj.type == "ARMATURE":
+                        if obj == objArmature:
+                            self.skeletonId = i
+                            break
+                        else:
+                            i += 1
+
+        # determine Position, rotation, & scaling
+        if forcedParent is None:
+            # Use local matrix
+            locMatrix = object.matrix_local
+            if objArmature != None:
+                # unless the armature is the parent
+                if object.parent and object.parent == objArmature:
+                    locMatrix = object.matrix_world * object.parent.matrix_world.inverted()
+
+            loc, rot, scale = locMatrix.decompose()
+            self.position = loc
+            if object.rotation_mode == 'QUATERNION':
+                self.rotationQuaternion = rot
+            else:
+                self.rotation = scale_vector(rot.to_euler('XYZ'), -1)
+            self.scaling  = scale
+        else:
+            # use defaults when not None
+            self.position = Vector((0, 0, 0))
+            self.rotation = scale_vector(Vector((0, 0, 0)), 1) # isn't scaling 0's by 1 same as 0?
+            self.scaling  = Vector((1, 1, 1))
+            
+        # ensure no unapplied rotation or scale, when there is an armature
+        self.hasUnappliedTransforms = (self.scaling.x != 1 or self.scaling.y != 1 or self.scaling.z != 1 or
+                (hasattr(self, 'rotation'          ) and (self.rotation          .x != 0 or self.rotation          .y != 0 or self.rotation          .z != 0)) or 
+                (hasattr(self, 'rotationQuaternion') and (self.rotationQuaternion.x != 0 or self.rotationQuaternion.y != 0 or self.rotationQuaternion.z != 0 or self.rotationQuaternion.w != 1))
+                )
+
+        # determine parent & dataName
+        if forcedParent is None:
+            self.dataName = object.data.name # used to support shared vertex instances in later passed
+            if object.parent and object.parent.type != 'ARMATURE':
+                self.parentId = object.parent.name
+        else:
+            self.dataName = self.name
+            self.parentId = forcedParent.name
+
+        # Get if this will be an instance of another, before processing materials, to avoid multi-bakes
+        sourceMesh = exporter.getSourceMeshInstance(self.dataName)
+        if sourceMesh is not None:
+            #need to make sure rotation mode matches, since value initially copied in InstancedMesh constructor
+            if hasattr(sourceMesh, 'rotationQuaternion'):
+                instRot = None
+                instRotq = rot
+            else:
+                instRot = scale_vector(rot.to_euler('XYZ'), -1)
+                instRotq = None
+
+            instance = MeshInstance(self, instRot, instRotq)
+            sourceMesh.instances.append(instance)
+            Logger.log('mesh is an instance of :  ' + sourceMesh.name + '.  Processing halted.', 2)
+            return
+        else:
+            self.instances = []
+
+        # Physics
+        if object.rigid_body != None:
+            shape_items = {'SPHERE'     : SPHERE_IMPOSTER,
+                           'BOX'        : BOX_IMPOSTER,
+                           'MESH'       : MESH_IMPOSTER,
+                           'CAPSULE'    : CAPSULE_IMPOSTER,
+                           'CONE'       : CONE_IMPOSTER,
+                           'CYLINDER'   : CYLINDER_IMPOSTER,
+                           'CONVEX_HULL': CONVEX_HULL_IMPOSTER}
+
+            shape_type = shape_items[object.rigid_body.collision_shape]
+            self.physicsImpostor = shape_type
+            mass = object.rigid_body.mass
+            if mass < 0.005:
+                mass = 0
+            self.physicsMass = mass
+            self.physicsFriction = object.rigid_body.friction
+            self.physicsRestitution = object.rigid_body.restitution
+
+        # process all of the materials required
+        maxVerts = MAX_VERTEX_ELEMENTS # change for multi-materials
+        recipe = BakingRecipe(object)
+        self.billboardMode = BILLBOARDMODE_ALL if recipe.isBillboard else BILLBOARDMODE_NONE
+
+        if recipe.needsBaking:
+            if recipe.multipleRenders:
+                Logger.warn('Mixing of Cycles & Blender Render in same mesh not supported.  No materials exported.', 2)
+            else:
+                bakedMat = BakedMaterial(exporter, object, recipe)
+                exporter.materials.append(bakedMat)
+                self.materialId = bakedMat.name
+
+        else:
+            bjs_material_slots = []
+            for slot in object.material_slots:
+                # None will be returned when either the first encounter or must be unique due to baked textures
+                material = exporter.getMaterial(slot.name)
+                if (material != None):
+                    Logger.log('registered as also a user of material:  ' + slot.name, 2)
+                else:
+                    material = StdMaterial(slot, exporter, object)
+                    exporter.materials.append(material)
+
+                bjs_material_slots.append(material)
+
+            if len(bjs_material_slots) == 1:
+                self.materialId = bjs_material_slots[0].name
+
+            elif len(bjs_material_slots) > 1:
+                multimat = MultiMaterial(bjs_material_slots, len(exporter.multiMaterials), exporter.nameSpace)
+                self.materialId = multimat.name
+                exporter.multiMaterials.append(multimat)
+                maxVerts = MAX_VERTEX_ELEMENTS_32Bit
+            else:
+                Logger.warn('No materials have been assigned: ', 2)
+
+        # Get mesh
+        mesh = object.to_mesh(scene, True, 'PREVIEW')
+
+        # Triangulate mesh if required
+        Mesh.mesh_triangulate(mesh)
+
+        # Getting vertices and indices
+        self.positions  = []
+        self.normals    = []
+        self.uvs        = [] # not always used
+        self.uvs2       = [] # not always used
+        self.colors     = [] # not always used
+        self.indices    = []
+        self.subMeshes  = []
+
+        hasUV = len(mesh.tessface_uv_textures) > 0
+        if hasUV:
+            which = len(mesh.tessface_uv_textures) - 1 if recipe.needsBaking else 0
+            UVmap = mesh.tessface_uv_textures[which].data
+
+        hasUV2 = len(mesh.tessface_uv_textures) > 1 and not recipe.needsBaking
+        if hasUV2:
+            UV2map = mesh.tessface_uv_textures[1].data
+
+        hasVertexColor = len(mesh.vertex_colors) > 0
+        if hasVertexColor:
+            Colormap = mesh.tessface_vertex_colors.active.data
+
+        if hasSkeleton:
+            weightsPerVertex = []
+            indicesPerVertex = []
+            influenceCounts = [0, 0, 0, 0, 0, 0, 0, 0, 0] # 9, so accessed orign 1; 0 used for all those greater than 8
+            totalInfluencers = 0
+            highestInfluenceObserved = 0
+
+        # used tracking of vertices as they are received
+        alreadySavedVertices = []
+        vertices_Normals = []
+        vertices_UVs = []
+        vertices_UV2s = []
+        vertices_Colors = []
+        vertices_indices = []
+        vertices_sk_weights = []
+        vertices_sk_indices = []
+
+        self.offsetFace = 0
+
+        for v in range(0, len(mesh.vertices)):
+            alreadySavedVertices.append(False)
+            vertices_Normals.append([])
+            vertices_UVs.append([])
+            vertices_UV2s.append([])
+            vertices_Colors.append([])
+            vertices_indices.append([])
+            vertices_sk_weights.append([])
+            vertices_sk_indices.append([])
+
+        materialsCount = 1 if recipe.needsBaking else max(1, len(object.material_slots))
+        verticesCount = 0
+        indicesCount = 0
+
+        for materialIndex in range(materialsCount):
+            if self.offsetFace != 0:
+                break
+
+            subMeshVerticesStart = verticesCount
+            subMeshIndexStart = indicesCount
+
+            for faceIndex in range(startFace, len(mesh.tessfaces)):  # For each face
+                face = mesh.tessfaces[faceIndex]
+
+                if face.material_index != materialIndex and not recipe.needsBaking:
+                    continue
+
+                if verticesCount + 3 > maxVerts:
+                    self.offsetFace = faceIndex
+                    break
+
+                for v in range(3): # For each vertex in face
+                    vertex_index = face.vertices[v]
+
+                    vertex = mesh.vertices[vertex_index]
+                    position = vertex.co
+                    normal = face.normal if useFlatShading else vertex.normal
+
+                    #skeletons
+                    if hasSkeleton:
+                        matricesWeights = []
+                        matricesIndices = []
+
+                        # Getting influences
+                        for group in vertex.groups:
+                            index = group.group
+                            weight = group.weight
+
+                            for bone in objArmature.pose.bones:
+                                if object.vertex_groups[index].name == bone.name:
+                                    matricesWeights.append(weight)
+                                    matricesIndices.append(skeleton.get_index_of_bone(bone.name))
+
+                    # 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 useFlatShading
+                    if alreadySaved:
+                        alreadySaved = False
+
+                        # UV
+                        index_UV = 0
+                        for savedIndex in vertices_indices[vertex_index]:
+                            vNormal = vertices_Normals[vertex_index][index_UV]
+                            if not same_vertex(normal, vNormal):
+                                continue;
+
+                            if hasUV:
+                                vUV = vertices_UVs[vertex_index][index_UV]
+                                if not same_array(vertex_UV, vUV):
+                                    continue
+
+                            if hasUV2:
+                                vUV2 = vertices_UV2s[vertex_index][index_UV]
+                                if not same_array(vertex_UV2, vUV2):
+                                    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 hasSkeleton:
+                                vSkWeight = vertices_sk_weights[vertex_index]
+                                vSkIndices = vertices_sk_indices[vertex_index]
+                                if not same_array(vSkWeight[index_UV], matricesWeights) or not same_array(vSkIndices[index_UV], matricesIndices):
+                                    continue
+
+                            if vertices_indices[vertex_index][index_UV] >= subMeshVerticesStart:
+                                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
+
+                        vertices_Normals[vertex_index].append(normal)
+                        self.normals.append(normal)
+
+                        if hasUV:
+                            vertices_UVs[vertex_index].append(vertex_UV)
+                            self.uvs.append(vertex_UV[0])
+                            self.uvs.append(vertex_UV[1])
+                        if hasUV2:
+                            vertices_UV2s[vertex_index].append(vertex_UV2)
+                            self.uvs2.append(vertex_UV2[0])
+                            self.uvs2.append(vertex_UV2[1])
+                        if hasVertexColor:
+                            vertices_Colors[vertex_index].append(vertex_Color)
+                            self.colors.append(vertex_Color.r)
+                            self.colors.append(vertex_Color.g)
+                            self.colors.append(vertex_Color.b)
+                            self.colors.append(1.0)
+                        if hasSkeleton:
+                            vertices_sk_weights[vertex_index].append(matricesWeights)
+                            vertices_sk_indices[vertex_index].append(matricesIndices)
+                            nInfluencers = len(matricesWeights)
+                            totalInfluencers += nInfluencers
+                            if nInfluencers <= 8:
+                                influenceCounts[nInfluencers] += 1
+                            else:
+                                influenceCounts[0] += 1
+                            highestInfluenceObserved = nInfluencers if nInfluencers > highestInfluenceObserved else highestInfluenceObserved
+                            weightsPerVertex.append(matricesWeights)
+                            indicesPerVertex.append(matricesIndices)
+
+                        vertices_indices[vertex_index].append(index)
+
+                        self.positions.append(position)
+
+                        verticesCount += 1
+                    self.indices.append(index)
+                    indicesCount += 1
+
+            self.subMeshes.append(SubMesh(materialIndex, subMeshVerticesStart, subMeshIndexStart, verticesCount - subMeshVerticesStart, indicesCount - subMeshIndexStart))
+
+        if verticesCount > MAX_VERTEX_ELEMENTS:
+            Logger.warn('Due to multi-materials / Shapekeys & this meshes size, 32bit indices must be used.  This may not run on all hardware.', 2)
+
+        BakedMaterial.meshBakingClean(object)
+
+        Logger.log('num positions      :  ' + str(len(self.positions)), 2)
+        Logger.log('num normals        :  ' + str(len(self.normals  )), 2)
+        Logger.log('num uvs            :  ' + str(len(self.uvs      )), 2)
+        Logger.log('num uvs2           :  ' + str(len(self.uvs2     )), 2)
+        Logger.log('num colors         :  ' + str(len(self.colors   )), 2)
+        Logger.log('num indices        :  ' + str(len(self.indices  )), 2)
+        
+        if hasSkeleton:
+            Logger.log('Skeleton stats:  ', 2)
+            self.toFixedInfluencers(weightsPerVertex, indicesPerVertex, object.data.maxInfluencers, highestInfluenceObserved)
+
+            if (COMPRESS_MATRIX_INDICES):
+                self.skeletonIndices = Mesh.packSkeletonIndices(self.skeletonIndices)
+                if (self.numBoneInfluencers > 4):
+                    self.skeletonIndicesExtra = Mesh.packSkeletonIndices(self.skeletonIndicesExtra)
+
+            Logger.log('Total Influencers:  ' + format_f(totalInfluencers), 3)
+            Logger.log('Avg # of influencers per vertex:  ' + format_f(totalInfluencers / len(self.positions)), 3)
+            Logger.log('Highest # of influencers observed:  ' + str(highestInfluenceObserved) + ', num vertices with this:  ' + format_int(influenceCounts[highestInfluenceObserved if highestInfluenceObserved < 9 else 0]), 3)
+            Logger.log('exported as ' + str(self.numBoneInfluencers) + ' influencers', 3)
+            nWeights = len(self.skeletonWeights) + (len(self.skeletonWeightsExtra) if hasattr(self, 'skeletonWeightsExtra') else 0)
+            Logger.log('num skeletonWeights and skeletonIndices:  ' + str(nWeights), 3)
+
+        numZeroAreaFaces = self.find_zero_area_faces()
+        if numZeroAreaFaces > 0:
+            Logger.warn('# of 0 area faces found:  ' + str(numZeroAreaFaces), 2)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def find_zero_area_faces(self):
+        nFaces = int(len(self.indices) / 3)
+        nZeroAreaFaces = 0
+        for f in range(0, nFaces):
+            faceOffset = f * 3
+            p1 = self.positions[self.indices[faceOffset    ]]
+            p2 = self.positions[self.indices[faceOffset + 1]]
+            p3 = self.positions[self.indices[faceOffset + 2]]
+
+            if same_vertex(p1, p2) or same_vertex(p1, p3) or same_vertex(p2, p3): nZeroAreaFaces += 1
+
+        return nZeroAreaFaces
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    @staticmethod
+    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 toFixedInfluencers(self, weightsPerVertex, indicesPerVertex, maxInfluencers, highestObserved):
+        if (maxInfluencers > 8 or maxInfluencers < 1):
+            maxInfluencers = 8
+            Logger.warn('Maximum # of influencers invalid, set to 8', 3)
+
+        self.numBoneInfluencers = maxInfluencers if maxInfluencers < highestObserved else highestObserved
+        needExtras = self.numBoneInfluencers > 4
+
+        maxInfluencersExceeded = 0
+
+        fixedWeights = []
+        fixedIndices = []
+
+        fixedWeightsExtra = []
+        fixedIndicesExtra = []
+
+        for i in range(len(weightsPerVertex)):
+            weights = weightsPerVertex[i]
+            indices = indicesPerVertex[i]
+            nInfluencers = len(weights)
+
+            if (nInfluencers > self.numBoneInfluencers):
+                maxInfluencersExceeded += 1
+                Mesh.sortByDescendingInfluence(weights, indices)
+
+            for j in range(4):
+                fixedWeights.append(weights[j] if nInfluencers > j else 0.0)
+                fixedIndices.append(indices[j] if nInfluencers > j else 0  )
+
+            if needExtras:
+                for j in range(4, 8):
+                    fixedWeightsExtra.append(weights[j] if nInfluencers > j else 0.0)
+                    fixedIndicesExtra.append(indices[j] if nInfluencers > j else 0  )
+
+        self.skeletonWeights = fixedWeights
+        self.skeletonIndices = fixedIndices
+
+        if needExtras:
+            self.skeletonWeightsExtra = fixedWeightsExtra
+            self.skeletonIndicesExtra = fixedIndicesExtra
+
+        if maxInfluencersExceeded > 0:
+            Logger.warn('Maximum # of influencers exceeded for ' + format_int(maxInfluencersExceeded) + ' vertices, extras ignored', 3)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    # sorts one set of weights & indices by descending weight, by reference
+    # not shown to help with MakeHuman, but did not hurt.  In just so it is not lost for future.
+    @staticmethod
+    def sortByDescendingInfluence(weights, indices):
+        notSorted = True
+        while(notSorted):
+            notSorted = False
+            for idx in range(1, len(weights)):
+                if weights[idx - 1] < weights[idx]:
+                    tmp = weights[idx]
+                    weights[idx    ] = weights[idx - 1]
+                    weights[idx - 1] = tmp
+
+                    tmp = indices[idx]
+                    indices[idx    ] = indices[idx - 1]
+                    indices[idx - 1] = tmp
+
+                    notSorted = True
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    # assume that toFixedInfluencers has already run, which ensures indices length is a multiple of 4
+    @staticmethod
+    def packSkeletonIndices(indices):
+        compressedIndices = []
+
+        for i in range(math.floor(len(indices) / 4)):
+            idx = i * 4
+            matricesIndicesCompressed  = indices[idx    ]
+            matricesIndicesCompressed += indices[idx + 1] <<  8
+            matricesIndicesCompressed += indices[idx + 2] << 16
+            matricesIndicesCompressed += indices[idx + 3] << 24
+
+            compressedIndices.append(matricesIndicesCompressed)
+
+        return compressedIndices
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_string(file_handler, 'name', self.name, True)
+        write_string(file_handler, 'id', self.name)
+        if hasattr(self, 'parentId'): write_string(file_handler, 'parentId', self.parentId)
+
+        if hasattr(self, 'materialId'): write_string(file_handler, 'materialId', self.materialId)
+        write_int(file_handler, 'billboardMode', self.billboardMode)
+        write_vector(file_handler, 'position', self.position)
+
+        if hasattr(self, "rotationQuaternion"):
+            write_quaternion(file_handler, 'rotationQuaternion', self.rotationQuaternion)
+        else:
+            write_vector(file_handler, 'rotation', self.rotation)
+
+        write_vector(file_handler, 'scaling', self.scaling)
+        write_bool(file_handler, 'isVisible', self.isVisible)
+        write_bool(file_handler, 'freezeWorldMatrix', self.freezeWorldMatrix)
+        write_bool(file_handler, 'isEnabled', self.isEnabled)
+        write_bool(file_handler, 'checkCollisions', self.checkCollisions)
+        write_bool(file_handler, 'receiveShadows', self.receiveShadows)
+
+        if hasattr(self, 'physicsImpostor'):
+            write_int(file_handler, 'physicsImpostor', self.physicsImpostor)
+            write_float(file_handler, 'physicsMass', self.physicsMass)
+            write_float(file_handler, 'physicsFriction', self.physicsFriction)
+            write_float(file_handler, 'physicsRestitution', self.physicsRestitution)
+
+        # Geometry
+        if hasattr(self, 'skeletonId'):
+            write_int(file_handler, 'skeletonId', self.skeletonId)
+            write_int(file_handler, 'numBoneInfluencers', self.numBoneInfluencers)
+
+        write_vector_array(file_handler, 'positions', self.positions)
+        write_vector_array(file_handler, 'normals'  , self.normals  )
+
+        if len(self.uvs) > 0:
+            write_array(file_handler, 'uvs', self.uvs)
+
+        if len(self.uvs2) > 0:
+            write_array(file_handler, 'uvs2', self.uvs2)
+
+        if len(self.colors) > 0:
+            write_array(file_handler, 'colors', self.colors)
+
+        if hasattr(self, 'skeletonWeights'):
+            write_array(file_handler, 'matricesWeights', self.skeletonWeights)
+            write_array(file_handler, 'matricesIndices', self.skeletonIndices)
+
+        if hasattr(self, 'skeletonWeightsExtra'):
+            write_array(file_handler, 'matricesWeightsExtra', self.skeletonWeightsExtra)
+            write_array(file_handler, 'matricesIndicesExtra', self.skeletonIndicesExtra)
+
+        write_array(file_handler, 'indices', self.indices)
+
+        # Sub meshes
+        file_handler.write('\n,"subMeshes":[')
+        first = True
+        for subMesh in self.subMeshes:
+            if first == False:
+                file_handler.write(',')
+            subMesh.to_scene_file(file_handler)
+            first = False
+        file_handler.write(']')
+
+        super().to_scene_file(file_handler) # Animations
+
+        # Instances
+        first = True
+        file_handler.write('\n,"instances":[')
+        for instance in self.instances:
+            if first == False:
+                file_handler.write(',')
+
+            instance.to_scene_file(file_handler)
+
+            first = False
+        file_handler.write(']')
+
+        # Close mesh
+        file_handler.write('}\n')
+        self.alreadyExported = True
+#===============================================================================
+class MeshInstance:
+     def __init__(self, instancedMesh, rotation, rotationQuaternion):
+        self.name = instancedMesh.name
+        if hasattr(instancedMesh, 'parentId'): self.parentId = instancedMesh.parentId
+        self.position = instancedMesh.position
+        if rotation is not None:
+            self.rotation = rotation
+        if rotationQuaternion is not None:
+            self.rotationQuaternion = rotationQuaternion
+        self.scaling = instancedMesh.scaling
+        self.freezeWorldMatrix = instancedMesh.freezeWorldMatrix
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_string(file_handler, 'name', self.name, True)
+        if hasattr(self, 'parentId'): write_string(file_handler, 'parentId', self.parentId)
+        write_vector(file_handler, 'position', self.position)
+        if hasattr(self, 'rotation'):
+            write_vector(file_handler, 'rotation', self.rotation)
+        else:
+            write_quaternion(file_handler, 'rotationQuaternion', self.rotationQuaternion)
+
+        write_vector(file_handler, 'scaling', self.scaling)
+        # freeze World Matrix currently ignored for instances
+        write_bool(file_handler, 'freezeWorldMatrix', self.freezeWorldMatrix)
+        file_handler.write('}')
+#===============================================================================
+class Node(FCurveAnimatable):
+    def __init__(self, node):
+        Logger.log('processing begun of node:  ' + node.name)
+        self.define_animations(node, True, True, True)  #Should animations be done when forcedParent
+        self.name = node.name
+
+        if node.parent and node.parent.type != 'ARMATURE':
+            self.parentId = node.parent.name
+
+        loc, rot, scale = node.matrix_local.decompose()
+
+        self.position = loc
+        if node.rotation_mode == 'QUATERNION':
+            self.rotationQuaternion = rot
+        else:
+            self.rotation = scale_vector(rot.to_euler('XYZ'), -1)
+        self.scaling = scale
+        self.isVisible = False
+        self.isEnabled = True
+        self.checkCollisions = False
+        self.billboardMode = BILLBOARDMODE_NONE
+        self.castShadows = False
+        self.receiveShadows = False
+        self.layer = -1 # nodes do not have layers attribute
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_string(file_handler, 'name', self.name, True)
+        write_string(file_handler, 'id', self.name)
+        if hasattr(self, 'parentId'): write_string(file_handler, 'parentId', self.parentId)
+
+        write_vector(file_handler, 'position', self.position)
+        if hasattr(self, "rotationQuaternion"):
+            write_quaternion(file_handler, "rotationQuaternion", self.rotationQuaternion)
+        else:
+            write_vector(file_handler, 'rotation', self.rotation)
+        write_vector(file_handler, 'scaling', self.scaling)
+        write_bool(file_handler, 'isVisible', self.isVisible)
+        write_bool(file_handler, 'isEnabled', self.isEnabled)
+        write_bool(file_handler, 'checkCollisions', self.checkCollisions)
+        write_int(file_handler, 'billboardMode', self.billboardMode)
+        write_bool(file_handler, 'receiveShadows', self.receiveShadows)
+
+        super().to_scene_file(file_handler) # Animations
+        file_handler.write('}')
+#===============================================================================
+class SubMesh:
+    def __init__(self, materialIndex, verticesStart, indexStart, verticesCount, indexCount):
+        self.materialIndex = materialIndex
+        self.verticesStart = verticesStart
+        self.indexStart = indexStart
+        self.verticesCount = verticesCount
+        self.indexCount = indexCount
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_int(file_handler, 'materialIndex', self.materialIndex, True)
+        write_int(file_handler, 'verticesStart', self.verticesStart)
+        write_int(file_handler, 'verticesCount', self.verticesCount)
+        write_int(file_handler, 'indexStart'   , self.indexStart)
+        write_int(file_handler, 'indexCount'   , self.indexCount)
+        file_handler.write('}')
+#===============================================================================
+bpy.types.Mesh.autoAnimate = bpy.props.BoolProperty(
+    name='Auto launch animations',
+    description='',
+    default = False
+)
+bpy.types.Mesh.useFlatShading = bpy.props.BoolProperty(
+    name='Use Flat Shading',
+    description='Use face normals.  Increases vertices.',
+    default = False
+)
+bpy.types.Mesh.checkCollisions = bpy.props.BoolProperty(
+    name='Check Collisions',
+    description='Indicates mesh should be checked that it does not run into anything.',
+    default = False
+)
+bpy.types.Mesh.castShadows = bpy.props.BoolProperty(
+    name='Cast Shadows',
+    description='',
+    default = False
+)
+bpy.types.Mesh.receiveShadows = bpy.props.BoolProperty(
+    name='Receive Shadows',
+    description='',
+    default = False
+)
+# not currently in use
+bpy.types.Mesh.forceBaking = bpy.props.BoolProperty(
+    name='Combine Multi-textures / resize',
+    description='Also good to adjust single texture\'s size /compression.',
+    default = False
+)
+# not currently in use
+bpy.types.Mesh.usePNG = bpy.props.BoolProperty(
+    name='Need Alpha',
+    description='Saved as PNG when alpha is required, else JPG.',
+    default = False
+)
+bpy.types.Mesh.bakeSize = bpy.props.IntProperty(
+    name='Texture Size',
+    description='Final dimensions of texture(s).  Not required to be a power of 2, but recommended.',
+    default = 1024
+)
+bpy.types.Mesh.bakeQuality = bpy.props.IntProperty(
+    name='Quality 1-100',
+    description='For JPG: The trade-off between Quality - File size(100 highest quality)\nFor PNG: amount of time spent for compression',
+    default = 50, min = 1, max = 100
+)
+bpy.types.Mesh.materialNameSpace = bpy.props.StringProperty(
+    name='Name Space',
+    description='Prefix to use for materials for sharing across .blends.',
+    default = DEFAULT_MATERIAL_NAMESPACE
+)
+bpy.types.Mesh.maxSimultaneousLights = bpy.props.IntProperty(
+    name='Max Simultaneous Lights 0 - 32',
+    description='BJS property set on each material of this mesh.\nSet higher for more complex lighting.\nSet lower for armatures on mobile',
+    default = 4, min = 0, max = 32
+)
+bpy.types.Mesh.checkReadyOnlyOnce = bpy.props.BoolProperty(
+    name='Check Ready Only Once',
+    description='When checked better CPU utilization.  Advanced user option.',
+    default = False
+)
+bpy.types.Mesh.freezeWorldMatrix = bpy.props.BoolProperty(
+    name='Freeze World Matrix',
+    description='Indicate the position, rotation, & scale do not change for performance reasons',
+    default = False
+)
+bpy.types.Mesh.loadDisabled = bpy.props.BoolProperty(
+    name='Load Disabled',
+    description='Indicate this mesh & children should not be active until enabled by code.',
+    default = False
+)
+bpy.types.Mesh.attachedSound = bpy.props.StringProperty(
+    name='Sound',
+    description='',
+    default = ''
+)
+bpy.types.Mesh.loopSound = bpy.props.BoolProperty(
+    name='Loop sound',
+    description='',
+    default = True
+)
+bpy.types.Mesh.autoPlaySound = bpy.props.BoolProperty(
+    name='Auto play sound',
+    description='',
+    default = True
+)
+bpy.types.Mesh.maxSoundDistance = bpy.props.FloatProperty(
+    name='Max sound distance',
+    description='',
+    default = 100
+)
+bpy.types.Mesh.ignoreSkeleton = bpy.props.BoolProperty(
+    name='Ignore',
+    description='Do not export assignment to a skeleton',
+    default = False
+)
+bpy.types.Mesh.maxInfluencers = bpy.props.IntProperty(
+    name='Max bone Influencers / Vertex',
+    description='When fewer than this are observed, the lower value is used.',
+    default = 8, min = 1, max = 8
+)
+
+#===============================================================================
+class MeshPanel(bpy.types.Panel):
+    bl_label = get_title()
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'WINDOW'
+    bl_context = 'data'
+    
+    @classmethod
+    def poll(cls, context):
+        ob = context.object
+        return ob is not None and isinstance(ob.data, bpy.types.Mesh)
+    
+    def draw(self, context):
+        ob = context.object
+        layout = self.layout  
+        row = layout.row()
+        row.prop(ob.data, 'useFlatShading')
+        row.prop(ob.data, 'checkCollisions')
+        
+        row = layout.row()
+        row.prop(ob.data, 'castShadows')
+        row.prop(ob.data, 'receiveShadows')
+        
+        row = layout.row()
+        row.prop(ob.data, 'freezeWorldMatrix')
+        row.prop(ob.data, 'loadDisabled')
+        
+        layout.prop(ob.data, 'autoAnimate')
+        
+        box = layout.box()
+        box.label(text='Skeleton:')
+        box.prop(ob.data, 'ignoreSkeleton')
+        row = box.row()
+        row.enabled = not ob.data.ignoreSkeleton
+        row.prop(ob.data, 'maxInfluencers')
+        
+        box = layout.box()
+        box.label('Materials')
+        box.prop(ob.data, 'materialNameSpace')
+        box.prop(ob.data, 'maxSimultaneousLights')
+        box.prop(ob.data, 'checkReadyOnlyOnce')
+        
+        box = layout.box()
+        box.label(text='Procedural Texture / Cycles Baking')
+#        box.prop(ob.data, 'forceBaking')
+#        box.prop(ob.data, 'usePNG')
+        box.prop(ob.data, 'bakeSize')
+        box.prop(ob.data, 'bakeQuality')
+        
+        box = layout.box()
+        box.prop(ob.data, 'attachedSound')
+        row = box.row()
+
+        row.prop(ob.data, 'autoPlaySound')
+        row.prop(ob.data, 'loopSound')
+        box.prop(ob.data, 'maxSoundDistance')

+ 266 - 0
Exporters/Blender/src/package_level.py

@@ -0,0 +1,266 @@
+from sys import modules
+from math import floor
+from mathutils import Euler, Matrix
+
+from bpy import app
+from time import strftime
+MAX_FLOAT_PRECISION_INT = 4
+MAX_FLOAT_PRECISION = '%.' + str(MAX_FLOAT_PRECISION_INT) + 'f'
+VERTEX_OUTPUT_PER_LINE = 50
+STRIP_LEADING_ZEROS_DEFAULT = False # false for .babylon
+#===============================================================================
+#  module level formatting methods, called from multiple classes
+#===============================================================================
+def get_title():
+    bl_info = get_bl_info()
+    return bl_info['name'] + ' ver ' + format_exporter_version(bl_info)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def format_exporter_version(bl_info = None):
+    if bl_info is None:
+        bl_info = get_bl_info()
+    exporterVersion = bl_info['version']
+    return str(exporterVersion[0]) + '.' + str(exporterVersion[1]) +  '.' + str(exporterVersion[2])
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def blenderMajorMinorVersion():
+    # in form of '2.77 (sub 0)'
+    split1 = app.version_string.partition('.') 
+    major = split1[0]
+    
+    split2 = split1[2].partition(' ')
+    minor = split2[0]
+    
+    return float(major + '.' + minor)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def verify_min_blender_version():
+    reqd = get_bl_info()['blender']
+    
+    # in form of '2.77 (sub 0)'
+    split1 = app.version_string.partition('.') 
+    major = int(split1[0])
+    if reqd[0] > major: return False
+    
+    split2 = split1[2].partition(' ')
+    minor = int(split2[0])
+    if reqd[1] > minor: return False
+    
+    split3 = split2[2].partition(' ')
+    revision = int(split3[2][:1])
+    if reqd[2] > revision: return False
+    
+    return True
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def getNameSpace(filepathMinusExtension):
+    # assign nameSpace, based on OS
+    if filepathMinusExtension.find('\\') != -1:
+        return legal_js_identifier(filepathMinusExtension.rpartition('\\')[2])
+    else:
+        return legal_js_identifier(filepathMinusExtension.rpartition('/')[2])
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def getLayer(obj):
+    # empties / nodes do not have layers
+    if not hasattr(obj, 'layers') : return -1;
+    for idx, layer in enumerate(obj.layers):
+        if layer:
+            return idx
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+# a class for getting the module name, exporter version, & reqd blender version in get_bl_info()
+class dummy: pass
+def get_bl_info():
+    # .__module__ is the 'name of package.module', so strip after dot
+    packageName = dummy.__module__.partition('.')[0]
+    return modules.get(packageName).bl_info
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def legal_js_identifier(input):
+    out = ''
+    prefix = ''
+    for char in input:
+        if len(out) == 0:
+            if char in '0123456789':
+                # cannot take the chance that leading numbers being chopped of cause name conflicts, e.g (01.R & 02.R)
+                prefix += char
+                continue
+            elif char.upper() not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
+                continue
+
+        legal = char if char.upper() in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_' else '_'
+        out += legal
+
+    if len(prefix) > 0:
+        out += '_' + prefix
+    return out
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def format_f(num, stripLeadingZero = STRIP_LEADING_ZEROS_DEFAULT):
+    s = MAX_FLOAT_PRECISION % num # rounds to N decimal places while changing to string
+    s = s.rstrip('0') # strip trailing zeroes
+    s = s.rstrip('.') # strip trailing .
+    s = '0' if s == '-0' else s # nuke -0
+    
+    if stripLeadingZero:
+        asNum = float(s)
+        if asNum != 0 and asNum > -1 and asNum < 1:
+            if asNum < 0:
+                s = '-' + s[2:]
+            else:
+                s = s[1:]
+        
+    return s
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def format_matrix4(matrix):
+    tempMatrix = matrix.copy()
+    tempMatrix.transpose()
+
+    ret = ''
+    first = True
+    for vect in tempMatrix:
+        if (first != True):
+            ret +=','
+        first = False;
+
+        ret += format_f(vect[0]) + ',' + format_f(vect[1]) + ',' + format_f(vect[2]) + ',' + format_f(vect[3])
+
+    return ret
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def format_array3(array):
+    return format_f(array[0]) + ',' + format_f(array[1]) + ',' + format_f(array[2])
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def format_array(array, indent = ''):
+    ret = ''
+    first = True
+    nOnLine = 0
+    for element in array:
+        if (first != True):
+            ret +=','
+        first = False;
+
+        ret += format_f(element)
+        nOnLine += 1
+
+        if nOnLine >= VERTEX_OUTPUT_PER_LINE:
+            ret += '\n' + indent
+            nOnLine = 0
+
+    return ret
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def format_color(color):
+    return format_f(color.r) + ',' + format_f(color.g) + ',' + format_f(color.b)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def format_vector(vector, switchYZ = True):
+    return format_f(vector.x) + ',' + format_f(vector.z) + ',' + format_f(vector.y) if switchYZ else format_f(vector.x) + ',' + format_f(vector.y) + ',' + format_f(vector.z)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def format_vector_array(vectorArray, indent = ''):
+    ret = ''
+    first = True
+    nOnLine = 0
+    for vector in vectorArray:
+        if (first != True):
+            ret +=','
+        first = False;
+
+        ret += format_vector(vector)
+        nOnLine += 3
+
+        if nOnLine >= VERTEX_OUTPUT_PER_LINE:
+            ret += '\n' + indent
+            nOnLine = 0
+
+    return ret
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def format_quaternion(quaternion):
+    return format_f(quaternion.x) + ',' + format_f(quaternion.z) + ',' + format_f(quaternion.y) + ',' + format_f(-quaternion.w)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def format_int(int):
+    candidate = str(int) # when int string of an int
+    if '.' in candidate:
+        return format_f(floor(int)) # format_f removes un-neccessary precision
+    else:
+        return candidate
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def format_bool(bool):
+    if bool:
+        return 'true'
+    else:
+        return 'false'
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def post_rotate_quaternion(quat, angle):
+    post = Euler((angle, 0.0, 0.0)).to_matrix()
+    mqtn = quat.to_matrix()
+    quat = (mqtn*post).to_quaternion()
+    return quat
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def scale_vector(vector, mult, xOffset = 0):
+    ret = vector.copy()
+    ret.x *= mult
+    ret.x += xOffset
+    ret.z *= mult
+    ret.y *= mult
+    return ret
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def same_matrix4(matA, matB):
+    if(matA is None or matB is None): return False
+    if (len(matA) != len(matB)): return False
+    for i in range(len(matA)):
+        if (format_f(matA[i][0]) != format_f(matB[i][0]) or
+            format_f(matA[i][1]) != format_f(matB[i][1]) or
+            format_f(matA[i][2]) != format_f(matB[i][2]) or
+            format_f(matA[i][3]) != format_f(matB[i][3]) ):
+            return False
+    return True
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def same_vertex(vertA, vertB):
+    if vertA is None or vertB is None: return False
+    
+    if (format_f(vertA.x) != format_f(vertB.x) or
+        format_f(vertA.y) != format_f(vertB.y) or
+        format_f(vertA.z) != format_f(vertB.z) ):
+        return False
+
+    return True
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+def same_array(arrayA, arrayB):
+    if(arrayA is None or arrayB is None): return False
+    if len(arrayA) != len(arrayB): return False
+    for i in range(len(arrayA)):
+        if format_f(arrayA[i]) != format_f(arrayB[i]) : return False
+
+    return True
+#===============================================================================
+# module level methods for writing JSON (.babylon) files
+#===============================================================================
+def write_matrix4(file_handler, name, matrix):
+    file_handler.write(',"' + name + '":[' + format_matrix4(matrix) + ']')
+
+def write_array(file_handler, name, array):
+    file_handler.write('\n,"' + name + '":[' + format_array(array) + ']')
+
+def write_array3(file_handler, name, array):
+    file_handler.write(',"' + name + '":[' + format_array3(array) + ']')
+
+def write_color(file_handler, name, color):
+    file_handler.write(',"' + name + '":[' + format_color(color) + ']')
+
+def write_vector(file_handler, name, vector, switchYZ = True):
+    file_handler.write(',"' + name + '":[' + format_vector(vector, switchYZ) + ']')
+
+def write_vector_array(file_handler, name, vectorArray):
+    file_handler.write('\n,"' + name + '":[' + format_vector_array(vectorArray) + ']')
+
+def write_quaternion(file_handler, name, quaternion):
+    file_handler.write(',"' + name  +'":[' + format_quaternion(quaternion) + ']')
+
+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 + '":' + format_f(float))
+
+def write_int(file_handler, name, int, noComma = False):
+    if noComma == False:
+        file_handler.write(',')
+    file_handler.write('"' + name + '":' + format_int(int))
+
+def write_bool(file_handler, name, bool, noComma = False):
+    if noComma == False:
+        file_handler.write(',')
+    file_handler.write('"' + name + '":' + format_bool(bool))

+ 23 - 0
Exporters/Blender/src/sound.py

@@ -0,0 +1,23 @@
+from .package_level import *
+
+import bpy
+#===============================================================================
+class Sound:
+    def __init__(self, name, autoplay, loop, connectedMesh = None):
+        self.name = name;
+        self.autoplay = autoplay
+        self.loop = loop
+        if connectedMesh != None:
+            self.connectedMeshId = connectedMesh.name
+            self.maxDistance = connectedMesh.data.maxSoundDistance
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_string(file_handler, 'name', self.name, True)
+        write_bool(file_handler, 'autoplay', self.autoplay)
+        write_bool(file_handler, 'loop', self.loop)
+
+        if hasattr(self, 'connectedMeshId'):
+            write_string(file_handler, 'connectedMeshId', self.connectedMeshId)
+            write_float(file_handler, 'maxDistance', self.maxDistance)
+        file_handler.write('}')

+ 45 - 0
Exporters/Blender/src/world.py

@@ -0,0 +1,45 @@
+from .logger import *
+from .package_level import *
+
+import bpy
+
+# used in World constructor, defined in BABYLON.Scene
+#FOGMODE_NONE = 0
+#FOGMODE_EXP = 1
+#FOGMODE_EXP2 = 2
+FOGMODE_LINEAR = 3
+#===============================================================================
+class World:
+    def __init__(self, scene):
+        self.autoClear = True
+        world = scene.world
+        if world:
+            self.ambient_color = world.ambient_color
+            self.clear_color   = world.horizon_color
+        else:
+            self.ambient_color = mathutils.Color((0.2, 0.2, 0.3))
+            self.clear_color   = mathutils.Color((0.0, 0.0, 0.0))
+
+        self.gravity = scene.gravity
+
+        if world and world.mist_settings.use_mist:
+            self.fogMode = FOGMODE_LINEAR
+            self.fogColor = world.horizon_color
+            self.fogStart = world.mist_settings.start
+            self.fogEnd = world.mist_settings.depth
+            self.fogDensity = 0.1
+
+        Logger.log('Python World class constructor completed')
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        write_bool(file_handler, 'autoClear', self.autoClear, True)
+        write_color(file_handler, 'clearColor', self.clear_color)
+        write_color(file_handler, 'ambientColor', self.ambient_color)
+        write_vector(file_handler, 'gravity', self.gravity)
+
+        if hasattr(self, 'fogMode'):
+            write_int(file_handler, 'fogMode', self.fogMode)
+            write_color(file_handler, 'fogColor', self.fogColor)
+            write_float(file_handler, 'fogStart', self.fogStart)
+            write_float(file_handler, 'fogEnd', self.fogEnd)
+            write_float(file_handler, 'fogDensity', self.fogDensity)

Exporters/FBX/3rdParty/Fbx2016.1/include/fbxsdk.h → Exporters/FBX/3rdParty/Fbx2017.0.1/include/fbxsdk.h


Exporters/FBX/3rdParty/Fbx2016.1/include/fbxsdk/core/arch/fbxalloc.h → Exporters/FBX/3rdParty/Fbx2017.0.1/include/fbxsdk/core/arch/fbxalloc.h


Exporters/FBX/3rdParty/Fbx2016.1/include/fbxsdk/core/arch/fbxarch.h → Exporters/FBX/3rdParty/Fbx2017.0.1/include/fbxsdk/core/arch/fbxarch.h


Exporters/FBX/3rdParty/Fbx2016.1/include/fbxsdk/core/arch/fbxdebug.h → Exporters/FBX/3rdParty/Fbx2017.0.1/include/fbxsdk/core/arch/fbxdebug.h


+ 0 - 0
Exporters/FBX/3rdParty/Fbx2016.1/include/fbxsdk/core/arch/fbxnew.h


Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio